GNUnet debian-0.24.3-29-g453fda2cf
 
Loading...
Searching...
No Matches
gnunet-service-arm.c File Reference

the automated restart manager service More...

#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_arm_service.h"
#include "gnunet_protocols.h"
#include "arm.h"
Include dependency graph for gnunet-service-arm.c:

Go to the source code of this file.

Data Structures

struct  ServiceListeningInfo
 Record with information about a listen socket we have open. More...
 
struct  ServiceList
 List of our services. More...
 

Macros

#define LOG(kind, ...)   GNUNET_log_from (kind, "util", __VA_ARGS__)
 
#define LOG_STRERROR(kind, syscall)    GNUNET_log_from_strerror (kind, "util", syscall)
 
#define MAX_NOTIFY_QUEUE   1024
 How many messages do we queue up at most for optional notifications to a client? (this can cause notifications about outgoing messages to be dropped).
 

Functions

static void add_unixpath (struct sockaddr **saddrs, socklen_t *saddrlens, const char *unixpath, int abstract)
 Add the given UNIX domain path as an address to the list (as the first entry).
 
static int get_server_addresses (const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg_, struct sockaddr ***addrs, socklen_t **addr_lens)
 Get the list of addresses that a server for the given service should bind to.
 
static void signal_result (struct GNUNET_SERVICE_Client *client, const char *name, uint64_t request_id, enum GNUNET_ARM_Result result)
 Signal our client that we will start or stop the service.
 
static void broadcast_status (const char *name, enum GNUNET_ARM_ServiceMonitorStatus status, struct GNUNET_SERVICE_Client *unicast)
 Tell all clients about status change of a service.
 
static void start_process (struct ServiceList *sl, struct GNUNET_SERVICE_Client *client, uint64_t request_id)
 Actually start the process for the given service.
 
static struct ServiceListfind_service (const char *name)
 Find the process with the given service name in the given list and return it.
 
static void accept_connection (void *cls)
 First connection has come to the listening socket associated with the service, create the service in order to relay the incoming connection to it.
 
static void create_listen_socket (struct sockaddr *sa, socklen_t addr_len, struct ServiceList *sl)
 Creating a listening socket for each of the service's addresses and wait for the first incoming connection to it.
 
static void free_service (struct ServiceList *sl)
 Remove and free an entry in the service list.
 
static int check_start (void *cls, const struct GNUNET_ARM_Message *amsg)
 Check START-message.
 
static void handle_start (void *cls, const struct GNUNET_ARM_Message *amsg)
 Handle START-message.
 
static void trigger_shutdown (void *cls)
 Start a shutdown sequence.
 
static int check_stop (void *cls, const struct GNUNET_ARM_Message *amsg)
 Check STOP-message.
 
static void handle_stop (void *cls, const struct GNUNET_ARM_Message *amsg)
 Handle STOP-message.
 
static int pool_write (char *pool_start, size_t pool_size, size_t *pool_pos, char *str)
 Write a string to a string pool.
 
static void handle_list (void *cls, const struct GNUNET_ARM_Message *request)
 Handle LIST-message.
 
static void handle_test (void *cls, const struct GNUNET_MessageHeader *message)
 Handle TEST-message by sending back TEST.
 
static void do_shutdown ()
 We are done with everything.
 
static unsigned int list_count (struct ServiceList *run_head)
 Count how many services are still active.
 
static void shutdown_task (void *cls)
 Task run for shutdown.
 
static void delayed_restart_task (void *cls)
 Task run whenever it is time to restart a child that died.
 
static void maint_child_death (void *cls)
 Task triggered whenever we receive a SIGCHLD (child process died).
 
static void sighandler_child_death ()
 Signal handler called for SIGCHLD.
 
static void setup_service (void *cls, const char *section)
 Setup our service record for the given section in the configuration file (assuming the section is for a service).
 
static void * client_connect_cb (void *cls, struct GNUNET_SERVICE_Client *client, struct GNUNET_MQ_Handle *mq)
 A client connected, mark as a monitoring client.
 
static void client_disconnect_cb (void *cls, struct GNUNET_SERVICE_Client *client, void *app_ctx)
 A client disconnected, clean up associated state.
 
static void handle_monitor (void *cls, const struct GNUNET_MessageHeader *message)
 Handle MONITOR-message.
 
static void run (void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *serv)
 Process arm requests.
 
int main (int argc, char *const *argv)
 The main function for the arm service.
 

Variables

static struct ServiceListrunning_head
 List of running services.
 
static struct ServiceListrunning_tail
 List of running services.
 
static const struct GNUNET_CONFIGURATION_Handlecfg
 Our configuration.
 
static char * prefix_command
 Command to prepend to each actual command.
 
static char * final_option
 Option to append to each actual command.
 
static struct GNUNET_SCHEDULER_Taskchild_death_task
 ID of task called whenever we get a SIGCHILD.
 
static struct GNUNET_SCHEDULER_Taskchild_restart_task
 ID of task called whenever the timeout for restarting a child expires.
 
static struct GNUNET_DISK_PipeHandlesigpipe
 Pipe used to communicate shutdown via signal.
 
static int in_shutdown
 Are we in shutdown mode?
 
static int global_ret
 Return value from main.
 
static int start_user = GNUNET_YES
 Are we starting user services?
 
static int start_system = GNUNET_YES
 Are we starting system services?
 
static struct GNUNET_SERVICE_Handleservice
 Handle to our service instance.
 
static struct GNUNET_NotificationContextnotifier
 Context for notifications we need to send to our clients.
 

Detailed Description

the automated restart manager service

Author
Christian Grothoff

Definition in file gnunet-service-arm.c.

Macro Definition Documentation

◆ LOG

#define LOG (   kind,
  ... 
)    GNUNET_log_from (kind, "util", __VA_ARGS__)

Definition at line 32 of file gnunet-service-arm.c.

◆ LOG_STRERROR

#define LOG_STRERROR (   kind,
  syscall 
)     GNUNET_log_from_strerror (kind, "util", syscall)

Definition at line 34 of file gnunet-service-arm.c.

68{
73
78
82 struct sockaddr *service_addr;
83
87 struct ServiceList *sl;
88
92 socklen_t service_addr_len;
93
97 struct GNUNET_NETWORK_Handle *listen_socket;
98
102 struct GNUNET_SCHEDULER_Task *accept_task;
103};
104
105
109struct ServiceList
110{
114 struct ServiceList *next;
115
119 struct ServiceList *prev;
120
125
130
134 char *name;
135
139 char *binary;
140
144 char *config;
145
151
156
160 struct GNUNET_OS_Process *proc;
161
166
171
176
182
188 int force_start;
189
194 int pipe_control;
195
200};
201
205static struct ServiceList *running_head;
206
210static struct ServiceList *running_tail;
211
215static const struct GNUNET_CONFIGURATION_Handle *cfg;
216
220static char *prefix_command;
221
225static char *final_option;
226
231
237
241static struct GNUNET_DISK_PipeHandle *sigpipe;
242
246static int in_shutdown;
247
251static int global_ret;
252
256static int start_user = GNUNET_YES;
257
261static int start_system = GNUNET_YES;
262
273static struct GNUNET_SERVICE_Handle *service;
274
279
280
291static void
292add_unixpath (struct sockaddr **saddrs,
293 socklen_t *saddrlens,
294 const char *unixpath,
295 int abstract)
296{
297#ifdef AF_UNIX
298 struct sockaddr_un *un;
299
300 un = GNUNET_new (struct sockaddr_un);
301 un->sun_family = AF_UNIX;
302 GNUNET_strlcpy (un->sun_path, unixpath, sizeof(un->sun_path));
303#ifdef __linux__
304 if (GNUNET_YES == abstract)
305 un->sun_path[0] = '\0';
306#endif
307#if HAVE_SOCKADDR_UN_SUN_LEN
308 un->sun_len = (u_char) sizeof(struct sockaddr_un);
309#endif
310 *saddrs = (struct sockaddr *) un;
311 *saddrlens = sizeof(struct sockaddr_un);
312#else
313 /* this function should never be called
314 * unless AF_UNIX is defined! */
315 GNUNET_assert (0);
316#endif
317}
318
319
340static int
342 const struct GNUNET_CONFIGURATION_Handle *cfg_,
343 struct sockaddr ***addrs,
344 socklen_t **addr_lens)
345{
346 int disablev6;
347 struct GNUNET_NETWORK_Handle *desc;
348 unsigned long long port;
349 char *unixpath;
350 struct addrinfo hints;
351 struct addrinfo *res;
352 struct addrinfo *pos;
353 struct addrinfo *next;
354 unsigned int i;
355 int resi;
356 int ret;
357 int abstract;
358 struct sockaddr **saddrs;
359 socklen_t *saddrlens;
360 char *hostname;
361
362 *addrs = NULL;
363 *addr_lens = NULL;
364 desc = NULL;
365 disablev6 = GNUNET_NO;
366 if (GNUNET_SYSERR ==
367 (disablev6 = GNUNET_CONFIGURATION_get_value_yesno (cfg_,
369 "DISABLEV6")))
370 return GNUNET_SYSERR;
371 if (! disablev6)
372 {
373 /* probe IPv6 support */
374 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
375 if (NULL == desc)
376 {
377 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
378 (EACCES == errno))
379 {
381 return GNUNET_SYSERR;
382 }
384 _ (
385 "Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
387 strerror (errno));
388 disablev6 = GNUNET_YES;
389 }
390 else
391 {
393 }
394 }
395
396 port = 0;
398 {
399 if (GNUNET_OK !=
402 "PORT",
403 &port))
404 {
406 _ ("Require valid port number for service `%s' in configuration!\n"),
408 }
409 if (port > 65535)
410 {
412 _ ("Require valid port number for service `%s' in configuration!\n"),
414 return GNUNET_SYSERR;
415 }
416 }
417
418 hostname = NULL;
422 "BINDTO",
423 &hostname));
424 unixpath = NULL;
425 abstract = GNUNET_NO;
426#ifdef AF_UNIX
427 if ( (GNUNET_OK ==
430 "UNIXPATH",
431 &unixpath)) &&
432 (0 < strlen (unixpath)) )
433 {
434 /* probe UNIX support */
435 struct sockaddr_un s_un;
436
437 if (strlen (unixpath) >= sizeof(s_un.sun_path))
438 {
440 _ ("UNIXPATH `%s' too long, maximum length is %llu\n"),
441 unixpath,
442 (unsigned long long) sizeof(s_un.sun_path));
443 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
444 LOG (GNUNET_ERROR_TYPE_INFO, _ ("Using `%s' instead\n"), unixpath);
445 }
446#ifdef __linux__
448 "TESTING",
449 "USE_ABSTRACT_SOCKETS");
450 if (GNUNET_SYSERR == abstract)
451 abstract = GNUNET_NO;
452#endif
453 if ((GNUNET_YES != abstract) &&
456 }
457 if (NULL != unixpath)
458 {
459 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
460 if (NULL == desc)
461 {
462 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
463 (EACCES == errno))
464 {
466 GNUNET_free (hostname);
467 GNUNET_free (unixpath);
468 return GNUNET_SYSERR;
469 }
471 _ (
472 "Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
474 strerror (errno));
475 GNUNET_free (unixpath);
476 unixpath = NULL;
477 }
478 else
479 {
481 desc = NULL;
482 }
483 }
484#endif
485
486 if ((0 == port) && (NULL == unixpath))
487 {
488 if (GNUNET_YES ==
491 "START_ON_DEMAND"))
493 _ (
494 "Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
496 GNUNET_free (hostname);
497 return GNUNET_SYSERR;
498 }
499 if (0 == port)
500 {
501 saddrs = GNUNET_new_array (2, struct sockaddr *);
502 saddrlens = GNUNET_new_array (2, socklen_t);
503 add_unixpath (saddrs, saddrlens, unixpath, abstract);
504 GNUNET_free (unixpath);
505 GNUNET_free (hostname);
506 *addrs = saddrs;
507 *addr_lens = saddrlens;
508 return 1;
509 }
510
511 if (NULL != hostname)
512 {
514 "Resolving `%s' since that is where `%s' will bind to.\n",
515 hostname,
517 memset (&hints, 0, sizeof(struct addrinfo));
518 if (disablev6)
519 hints.ai_family = AF_INET;
520 hints.ai_protocol = IPPROTO_TCP;
521 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
522 (NULL == res))
523 {
525 _ ("Failed to resolve `%s': %s\n"),
526 hostname,
527 gai_strerror (ret));
528 GNUNET_free (hostname);
529 GNUNET_free (unixpath);
530 return GNUNET_SYSERR;
531 }
532 next = res;
533 i = 0;
534 while (NULL != (pos = next))
535 {
536 next = pos->ai_next;
537 if ((disablev6) && (pos->ai_family == AF_INET6))
538 continue;
539 i++;
540 }
541 if (0 == i)
542 {
544 _ ("Failed to find %saddress for `%s'.\n"),
545 disablev6 ? "IPv4 " : "",
546 hostname);
547 freeaddrinfo (res);
548 GNUNET_free (hostname);
549 GNUNET_free (unixpath);
550 return GNUNET_SYSERR;
551 }
552 resi = i;
553 if (NULL != unixpath)
554 resi++;
555 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
556 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
557 i = 0;
558 if (NULL != unixpath)
559 {
560 add_unixpath (saddrs, saddrlens, unixpath, abstract);
561 i++;
562 }
563 next = res;
564 while (NULL != (pos = next))
565 {
566 next = pos->ai_next;
567 if ((disablev6) && (AF_INET6 == pos->ai_family))
568 continue;
569 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
570 continue; /* not TCP */
571 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
572 continue; /* huh? */
574 "Service `%s' will bind to `%s'\n",
576 GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
577 if (AF_INET == pos->ai_family)
578 {
579 GNUNET_assert (sizeof(struct sockaddr_in) == pos->ai_addrlen);
580 saddrlens[i] = pos->ai_addrlen;
581 saddrs[i] = GNUNET_malloc (saddrlens[i]);
582 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
583 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
584 }
585 else
586 {
587 GNUNET_assert (AF_INET6 == pos->ai_family);
588 GNUNET_assert (sizeof(struct sockaddr_in6) == pos->ai_addrlen);
589 saddrlens[i] = pos->ai_addrlen;
590 saddrs[i] = GNUNET_malloc (saddrlens[i]);
591 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
592 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
593 }
594 i++;
595 }
596 GNUNET_free (hostname);
597 freeaddrinfo (res);
598 resi = i;
599 }
600 else
601 {
602 /* will bind against everything, just set port */
603 if (disablev6)
604 {
605 /* V4-only */
606 resi = 1;
607 if (NULL != unixpath)
608 resi++;
609 i = 0;
610 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
611 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
612 if (NULL != unixpath)
613 {
614 add_unixpath (saddrs, saddrlens, unixpath, abstract);
615 i++;
616 }
617 saddrlens[i] = sizeof(struct sockaddr_in);
618 saddrs[i] = GNUNET_malloc (saddrlens[i]);
619#if HAVE_SOCKADDR_IN_SIN_LEN
620 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
621#endif
622 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
623 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
624 }
625 else
626 {
627 /* dual stack */
628 resi = 2;
629 if (NULL != unixpath)
630 resi++;
631 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
632 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
633 i = 0;
634 if (NULL != unixpath)
635 {
636 add_unixpath (saddrs, saddrlens, unixpath, abstract);
637 i++;
638 }
639 saddrlens[i] = sizeof(struct sockaddr_in6);
640 saddrs[i] = GNUNET_malloc (saddrlens[i]);
641#if HAVE_SOCKADDR_IN_SIN_LEN
642 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
643#endif
644 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
645 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
646 i++;
647 saddrlens[i] = sizeof(struct sockaddr_in);
648 saddrs[i] = GNUNET_malloc (saddrlens[i]);
649#if HAVE_SOCKADDR_IN_SIN_LEN
650 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
651#endif
652 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
653 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
654 }
655 }
656 GNUNET_free (unixpath);
657 *addrs = saddrs;
658 *addr_lens = saddrlens;
659 return resi;
660}
661
662
673static void
675 const char *name,
676 uint64_t request_id,
678{
679 struct GNUNET_MQ_Envelope *env;
681
682 (void) name;
684 msg->result = htonl (result);
685 msg->arm_msg.request_id = GNUNET_htonll (request_id);
687}
688
689
698static void
699broadcast_status (const char *name,
701 struct GNUNET_SERVICE_Client *unicast)
702{
703 struct GNUNET_MQ_Envelope *env;
705 size_t namelen;
706
708 "Sending status %u of service `%s' to client\n",
709 (unsigned int) status,
710 name);
711 namelen = strlen (name) + 1;
713 namelen,
715 msg->status = htonl ((uint32_t) (status));
716 GNUNET_memcpy ((char *) &msg[1],
717 name,
718 namelen);
719 if (NULL == unicast)
720 {
721 if (NULL != notifier)
723 &msg->header,
724 GNUNET_YES);
726 }
727 else
728 {
730 env);
731 }
732}
733
734
743static void
744start_process (struct ServiceList *sl,
745 struct GNUNET_SERVICE_Client *client,
746 uint64_t request_id)
747{
748 char *loprefix;
749 char *options;
750 enum GNUNET_GenericReturnValue use_debug;
751 bool is_simple_service;
752 int *lsocks;
753 unsigned int ls;
754 char *binary;
755 char *quotedbinary;
756
757 /* calculate listen socket list */
758 lsocks = NULL;
759 ls = 0;
760 for (struct ServiceListeningInfo *sli = sl->listen_head;
761 NULL != sli;
762 sli = sli->next)
763 {
764 GNUNET_array_append (lsocks,
765 ls,
766 GNUNET_NETWORK_get_fd (sli->listen_socket));
767 if (NULL != sli->accept_task)
768 {
769 GNUNET_SCHEDULER_cancel (sli->accept_task);
770 sli->accept_task = NULL;
771 }
772 }
773
774 GNUNET_array_append (lsocks,
775 ls,
776 -1);
777
778 /* obtain configuration */
779 if (GNUNET_OK !=
781 sl->name,
782 "PREFIX",
783 &loprefix))
784 loprefix = GNUNET_strdup (prefix_command);
785 else
787 loprefix);
788 if (GNUNET_OK !=
790 sl->name,
791 "OPTIONS",
792 &options))
793 options = NULL;
794 else
796 {
797 char *new_options;
798 char *optpos;
799 char *fin_options;
800
801 fin_options = GNUNET_strdup (final_option);
802 /* replace '{}' with service name */
803 while (NULL != (optpos = strstr (fin_options, "{}")))
804 {
805 /* terminate string at opening parenthesis */
806 *optpos = 0;
807 GNUNET_asprintf (&new_options,
808 "%s%s%s",
809 fin_options,
810 sl->name,
811 optpos + 2);
812 GNUNET_free (fin_options);
813 fin_options = new_options;
814 }
815 if (NULL != options)
816 {
817 /* combine "fin_options" with "options" */
818 optpos = options;
819 GNUNET_asprintf (&options, "%s %s", fin_options, optpos);
820 GNUNET_free (fin_options);
821 GNUNET_free (optpos);
822 }
823 else
824 {
825 /* only have "fin_options", use that */
826 options = fin_options;
827 }
828 }
830 options);
832 sl->name,
833 "DEBUG");
834 {
835 const char *service_type = NULL;
836 const char *choices[] = {
837 "GNUNET",
838 "SIMPLE",
839 NULL
840 };
841
842 is_simple_service = false;
843 if ( (GNUNET_OK ==
845 sl->name,
846 "TYPE",
847 choices,
848 &service_type)) &&
849 (0 == strcasecmp (service_type,
850 "SIMPLE")))
851 is_simple_service = true;
852 }
853
854 GNUNET_assert (NULL == sl->proc);
855 if (is_simple_service)
856 {
857 /* A simple service will receive no GNUnet specific
858 command line options. */
859 binary = GNUNET_strdup (sl->binary);
861 binary);
862 GNUNET_asprintf (&quotedbinary,
863 "\"%s\"",
864 sl->binary);
866 "Starting simple service `%s' using binary `%s'\n",
867 sl->name,
868 sl->binary);
869 /* FIXME: dollar expansion should only be done outside
870 * of ''-quoted strings, escaping should be considered. */
871 if (NULL != options)
873 options);
878 lsocks,
879 loprefix,
880 quotedbinary,
881 options,
882 NULL);
883 }
884 else
885 {
886 /* actually start process */
888 "Starting service `%s' using binary `%s' and configuration `%s'\n",
889 sl->name,
890 sl->binary,
891 sl->config);
893 ,
894 sl->binary);
895 GNUNET_asprintf (&quotedbinary,
896 "\"%s\"",
897 binary);
898
899 if (GNUNET_YES == use_debug)
900 {
901 if (NULL == sl->config)
903 sl->pipe_control
907 lsocks,
908 loprefix,
909 quotedbinary,
910 "-L",
911 "DEBUG",
912 options,
913 NULL);
914 else
916 sl->pipe_control
920 lsocks,
921 loprefix,
922 quotedbinary,
923 "-c",
924 sl->config,
925 "-L",
926 "DEBUG",
927 options,
928 NULL);
929 }
930 else
931 {
932 if (NULL == sl->config)
934 sl->pipe_control
938 lsocks,
939 loprefix,
940 quotedbinary,
941 options,
942 NULL);
943 else
945 sl->pipe_control
949 lsocks,
950 loprefix,
951 quotedbinary,
952 "-c",
953 sl->config,
954 options,
955 NULL);
956 }
957 }
958 GNUNET_free (binary);
959 GNUNET_free (quotedbinary);
961 if (NULL == sl->proc)
962 {
964 "Failed to start service `%s'\n",
965 sl->name);
966 if (client)
967 signal_result (client,
968 sl->name,
969 request_id,
971 }
972 else
973 {
975 "Starting service `%s'\n",
976 sl->name);
979 NULL);
980 if (client)
981 signal_result (client,
982 sl->name,
983 request_id,
985 }
986 /* clean up */
987 GNUNET_free (loprefix);
989 GNUNET_array_grow (lsocks,
990 ls,
991 0);
992}
993
994
1002static struct ServiceList *
1003find_service (const char *name)
1004{
1005 struct ServiceList *sl;
1006
1007 sl = running_head;
1008 while (sl != NULL)
1009 {
1010 if (0 == strcasecmp (sl->name, name))
1011 return sl;
1012 sl = sl->next;
1013 }
1014 return NULL;
1015}
1016
1017
1024static void
1025accept_connection (void *cls)
1026{
1027 struct ServiceListeningInfo *sli = cls;
1028 struct ServiceList *sl = sli->sl;
1029
1030 sli->accept_task = NULL;
1032 start_process (sl, NULL, 0);
1033}
1034
1035
1044static void
1045create_listen_socket (struct sockaddr *sa,
1046 socklen_t addr_len,
1047 struct ServiceList *sl)
1048{
1049 static int on = 1;
1050 struct GNUNET_NETWORK_Handle *sock;
1051 struct ServiceListeningInfo *sli;
1052
1053 int match_uid;
1054 int match_gid;
1055
1056 switch (sa->sa_family)
1057 {
1058 case AF_INET:
1059 sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
1060 break;
1061
1062 case AF_INET6:
1063 sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1064 break;
1065
1066 case AF_UNIX:
1067 if (0 == strcmp (GNUNET_a2s (sa, addr_len),
1068 "@")) /* Do not bind to blank UNIX path! */
1069 return;
1070 sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
1071 break;
1072
1073 default:
1074 GNUNET_break (0);
1075 sock = NULL;
1076 errno = EAFNOSUPPORT;
1077 break;
1078 }
1079 if (NULL == sock)
1080 {
1082 _ ("Unable to create socket for service `%s': %s\n"),
1083 sl->name,
1084 strerror (errno));
1085 GNUNET_free (sa);
1086 return;
1087 }
1089 SOL_SOCKET,
1090 SO_REUSEADDR,
1091 &on,
1092 sizeof(on)))
1094 "setsockopt");
1095#ifdef IPV6_V6ONLY
1096 if ((sa->sa_family == AF_INET6) &&
1098 IPPROTO_IPV6,
1099 IPV6_V6ONLY,
1100 &on,
1101 sizeof(on))))
1103 "setsockopt");
1104#endif
1105 if (AF_UNIX == sa->sa_family)
1106 GNUNET_NETWORK_unix_precheck ((struct sockaddr_un *) sa);
1107 if (GNUNET_OK !=
1108 GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) sa, addr_len))
1109 {
1110 GNUNET_log (
1112 _ (
1113 "Unable to bind listening socket for service `%s' to address `%s': %s\n"),
1114 sl->name,
1115 GNUNET_a2s (sa, addr_len),
1116 strerror (errno));
1118 GNUNET_free (sa);
1119 return;
1120 }
1121 if ((AF_UNIX == sa->sa_family)
1122#ifdef __linux__
1123 /* Permission settings are not required when abstract sockets are used */
1124 && ('\0' != ((const struct sockaddr_un *) sa)->sun_path[0])
1125#endif
1126 )
1127 {
1128 match_uid =
1129 (GNUNET_YES ==
1131 sl->name,
1132 "UNIX_MATCH_UID"));
1133 match_gid =
1134 (GNUNET_YES ==
1136 sl->name,
1137 "UNIX_MATCH_GID"));
1138 GNUNET_DISK_fix_permissions (((const struct sockaddr_un *) sa)->sun_path,
1139 match_uid,
1140 match_gid);
1141 }
1142 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
1143 {
1146 GNUNET_free (sa);
1147 return;
1148 }
1150 _ ("ARM now monitors connections to service `%s' at `%s'\n"),
1151 sl->name,
1152 GNUNET_a2s (sa, addr_len));
1153 sli = GNUNET_new (struct ServiceListeningInfo);
1154 sli->service_addr = sa;
1155 sli->service_addr_len = addr_len;
1156 sli->listen_socket = sock;
1157 sli->sl = sl;
1158 sli->accept_task =
1160 sock,
1162 sli);
1164}
1165
1166
1173static void
1174free_service (struct ServiceList *sl)
1175{
1178 GNUNET_assert (NULL == sl->listen_head);
1181 GNUNET_free (sl->name);
1182 GNUNET_free (sl);
1183}
1184
1185
1194static int
1195check_start (void *cls, const struct GNUNET_ARM_Message *amsg)
1196{
1197 (void) cls;
1199 return GNUNET_OK;
1200}
1201
1202
1209static void
1210handle_start (void *cls, const struct GNUNET_ARM_Message *amsg)
1211{
1212 struct GNUNET_SERVICE_Client *client = cls;
1213 const char *servicename;
1214 struct ServiceList *sl;
1215 uint64_t request_id;
1216
1217 request_id = GNUNET_ntohll (amsg->request_id);
1218 servicename = (const char *) &amsg[1];
1220 if (GNUNET_YES == in_shutdown)
1221 {
1222 signal_result (client,
1223 servicename,
1224 request_id,
1226 return;
1227 }
1228 sl = find_service (servicename);
1229 if (NULL == sl)
1230 {
1231 signal_result (client,
1232 servicename,
1233 request_id,
1235 return;
1236 }
1237 sl->force_start = GNUNET_YES;
1238 if (NULL != sl->proc)
1239 {
1240 signal_result (client,
1241 servicename,
1242 request_id,
1244 return;
1245 }
1246 start_process (sl, client, request_id);
1247}
1248
1249
1255static void
1256trigger_shutdown (void *cls)
1257{
1258 (void) cls;
1259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Triggering shutdown\n");
1261}
1262
1263
1272static int
1273check_stop (void *cls, const struct GNUNET_ARM_Message *amsg)
1274{
1275 (void) cls;
1277 return GNUNET_OK;
1278}
1279
1280
1287static void
1288handle_stop (void *cls, const struct GNUNET_ARM_Message *amsg)
1289{
1290 struct GNUNET_SERVICE_Client *client = cls;
1291 struct ServiceList *sl;
1292 const char *servicename;
1293 uint64_t request_id;
1294
1295 request_id = GNUNET_ntohll (amsg->request_id);
1296 servicename = (const char *) &amsg[1];
1298 _ ("Preparing to stop `%s'\n"),
1299 servicename);
1301 if (0 == strcasecmp (servicename, "arm"))
1302 {
1303 broadcast_status (servicename, GNUNET_ARM_SERVICE_STOPPING, NULL);
1304 signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_STOPPING);
1307 return;
1308 }
1309 sl = find_service (servicename);
1310 if (NULL == sl)
1311 {
1312 signal_result (client,
1313 servicename,
1314 request_id,
1316 return;
1317 }
1318 sl->force_start = GNUNET_NO;
1319 if (GNUNET_YES == in_shutdown)
1320 {
1321 /* shutdown in progress */
1322 signal_result (client,
1323 servicename,
1324 request_id,
1326 return;
1327 }
1328 if (NULL != sl->killing_client)
1329 {
1330 /* killing already in progress */
1331 signal_result (client,
1332 servicename,
1333 request_id,
1335 return;
1336 }
1337 if (NULL == sl->proc)
1338 {
1339 /* process is down */
1340 signal_result (client,
1341 servicename,
1342 request_id,
1344 return;
1345 }
1347 "Sending kill signal to service `%s', waiting for process to die.\n",
1348 servicename);
1349 broadcast_status (servicename, GNUNET_ARM_SERVICE_STOPPING, NULL);
1350 /* no signal_start - only when it's STOPPED */
1354 sl->killing_client = client;
1355 sl->killing_client_request_id = request_id;
1356}
1357
1358
1370static int
1371pool_write (char *pool_start, size_t pool_size, size_t *pool_pos, char *str)
1372{
1373 size_t next_pos = (*pool_pos) + strlen (str) + 1;
1374
1375 if (next_pos > pool_size)
1376 return GNUNET_SYSERR;
1377 memcpy (pool_start + *pool_pos, str, strlen (str) + 1);
1378 *pool_pos = next_pos;
1379 return GNUNET_OK;
1380}
1381
1382
1389static void
1390handle_list (void *cls, const struct GNUNET_ARM_Message *request)
1391{
1392 struct GNUNET_SERVICE_Client *client = cls;
1393 struct GNUNET_MQ_Envelope *env;
1395 size_t extra_size;
1396 struct ServiceList *sl;
1397 uint16_t count;
1398 size_t pool_size;
1399 size_t pool_pos;
1400 char *pool_start;
1402
1403 GNUNET_break_op (0 == ntohl (request->reserved));
1404 count = 0;
1405 pool_size = 0;
1406
1407 /* Do one pass over the list to compute the number of services
1408 * and the string pool size */
1409 for (sl = running_head; NULL != sl; sl = sl->next)
1410 {
1411 pool_size += strlen (sl->name) + 1;
1412 pool_size += strlen (sl->binary) + 1;
1413 count++;
1414 }
1415
1416 extra_size = pool_size + (count * sizeof (struct
1419 extra_size,
1421 msg->arm_msg.request_id = request->request_id;
1422 msg->count = htons (count);
1423
1424 ssm = (struct GNUNET_ARM_ServiceInfoMessage *) &msg[1];
1425 pool_start = (char *) (ssm + count);
1426 pool_pos = 0;
1427
1428 for (sl = running_head; NULL != sl; sl = sl->next)
1429 {
1430 ssm->name_index = htons ((uint16_t) pool_pos);
1431 GNUNET_assert (GNUNET_OK == pool_write (pool_start, pool_size, &pool_pos,
1432 sl->name));
1433 ssm->binary_index = htons ((uint16_t) pool_pos);
1434 GNUNET_assert (GNUNET_OK == pool_write (pool_start, pool_size, &pool_pos,
1435 sl->binary));
1436 if (NULL == sl->proc)
1437 {
1438 if (0 == sl->last_started_at.abs_value_us)
1439 {
1440 /* Process never started */
1442 }
1443 else if (0 == sl->last_exit_status)
1444 {
1446 }
1447 else
1448 {
1450 ssm->last_exit_status = htons (sl->last_exit_status);
1451 }
1452 }
1453 else if ((NULL != sl->killing_client) || (GNUNET_YES == in_shutdown))
1454 {
1456 }
1457 else
1458 {
1460 }
1463 ssm++;
1464 }
1467}
1468
1469
1476static void
1477handle_test (void *cls, const struct GNUNET_MessageHeader *message)
1478{
1479 struct GNUNET_SERVICE_Client *client = cls;
1480 struct GNUNET_MQ_Envelope *env;
1481 struct GNUNET_MessageHeader *msg;
1482
1483 (void) message;
1487}
1488
1489
1494static void
1495do_shutdown ()
1496{
1497 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Last shutdown phase\n");
1498 if (NULL != notifier)
1499 {
1501 notifier = NULL;
1502 }
1503 if (NULL != service)
1504 {
1506 service = NULL;
1507 }
1508 if (NULL != child_death_task)
1509 {
1511 child_death_task = NULL;
1512 }
1513}
1514
1515
1522static unsigned int
1523list_count (struct ServiceList *run_head)
1524{
1525 struct ServiceList *i;
1526 unsigned int res;
1527
1528 for (res = 0, i = run_head; NULL != i; i = i->next, res++)
1530 return res;
1531}
1532
1533
1539static void
1540shutdown_task (void *cls)
1541{
1542 struct ServiceList *pos;
1543 struct ServiceList *nxt;
1544 struct ServiceListeningInfo *sli;
1545
1546 (void) cls;
1547 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "First shutdown phase\n");
1548 if (NULL != child_restart_task)
1549 {
1551 child_restart_task = NULL;
1552 }
1554 /* first, stop listening */
1555 for (pos = running_head; NULL != pos; pos = pos->next)
1556 {
1557 while (NULL != (sli = pos->listen_head))
1558 {
1560 if (NULL != sli->accept_task)
1561 {
1563 sli->accept_task = NULL;
1564 }
1568 GNUNET_free (sli);
1569 }
1570 }
1571 /* then, shutdown all existing service processes */
1572 nxt = running_head;
1573 while (NULL != (pos = nxt))
1574 {
1575 nxt = pos->next;
1576 if (NULL != pos->proc)
1577 {
1578 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping service `%s'\n", pos->name);
1582 }
1583 else
1584 {
1585 free_service (pos);
1586 }
1587 }
1588 /* finally, should all service processes be already gone, terminate for real */
1589 if (NULL == running_head)
1590 do_shutdown ();
1591 else
1593 "Delaying shutdown, have %u children still running\n",
1595}
1596
1597
1603static void
1604delayed_restart_task (void *cls)
1605
1606{
1607 struct ServiceList *sl;
1608 struct GNUNET_TIME_Relative lowestRestartDelay;
1609 struct ServiceListeningInfo *sli;
1610
1611 (void) cls;
1612 child_restart_task = NULL;
1614 lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL;
1615
1616 /* check for services that need to be restarted due to
1617 * configuration changes or because the last restart failed */
1618 for (sl = running_head; NULL != sl; sl = sl->next)
1619 {
1620 if (NULL != sl->proc)
1621 continue;
1622 /* service is currently not running */
1624 {
1625 /* restart is now allowed */
1626 if (sl->force_start)
1627 {
1628 /* process should run by default, start immediately */
1630 _ ("Restarting service `%s'.\n"),
1631 sl->name);
1632 start_process (sl, NULL, 0);
1633 }
1634 else
1635 {
1636 /* process is run on-demand, ensure it is re-started if there is demand */
1637 for (sli = sl->listen_head; NULL != sli; sli = sli->next)
1638 if (NULL == sli->accept_task)
1639 {
1640 /* accept was actually paused, so start it again */
1641 sli->accept_task =
1643 sli->listen_socket,
1645 sli);
1646 }
1647 }
1648 }
1649 else
1650 {
1651 /* update calculation for earliest time to reactivate a service */
1652 lowestRestartDelay =
1653 GNUNET_TIME_relative_min (lowestRestartDelay,
1655 sl->restart_at));
1656 }
1657 }
1658 if (lowestRestartDelay.rel_value_us !=
1659 GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1660 {
1662 "Will restart process in %s\n",
1663 GNUNET_STRINGS_relative_time_to_string (lowestRestartDelay,
1664 GNUNET_YES));
1669 NULL);
1670 }
1671}
1672
1673
1680static void
1681maint_child_death (void *cls)
1682{
1683 struct ServiceList *pos;
1684 struct ServiceList *next;
1685 struct ServiceListeningInfo *sli;
1686 const char *statstr;
1687 int statcode;
1688 int ret;
1689 char c[16];
1690 enum GNUNET_OS_ProcessStatusType statusType;
1691 unsigned long statusCode;
1692 const struct GNUNET_DISK_FileHandle *pr;
1693
1694 (void) cls;
1696 child_death_task = NULL;
1697 /* consume the signal */
1698 GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof(c)));
1699
1700 /* check for services that died (WAITPID) */
1701 next = running_head;
1702 while (NULL != (pos = next))
1703 {
1704 next = pos->next;
1705
1706 if (NULL == pos->proc)
1707 {
1708 if (GNUNET_YES == in_shutdown)
1709 free_service (pos);
1710 continue;
1711 }
1712#if HAVE_WAIT4
1713 if (NULL != wait_file)
1714 {
1715 /* need to use 'wait4()' to obtain and log performance data */
1716 struct rusage ru;
1717 int status;
1718 pid_t pid;
1719
1721 ret = wait4 (pid, &status, WNOHANG, &ru);
1722 if (ret <= 0)
1723 continue; /* no process done */
1724 if (WIFEXITED (status))
1725 {
1726 statusType = GNUNET_OS_PROCESS_EXITED;
1727 statusCode = WEXITSTATUS (status);
1728 }
1729 else if (WIFSIGNALED (status))
1730 {
1731 statusType = GNUNET_OS_PROCESS_SIGNALED;
1732 statusCode = WTERMSIG (status);
1733 }
1734 else if (WIFSTOPPED (status))
1735 {
1736 statusType = GNUNET_OS_PROCESS_SIGNALED;
1737 statusCode = WSTOPSIG (status);
1738 }
1739#ifdef WIFCONTINUED
1740 else if (WIFCONTINUED (status))
1741 {
1742 statusType = GNUNET_OS_PROCESS_RUNNING;
1743 statusCode = 0;
1744 }
1745#endif
1746 else
1747 {
1748 statusType = GNUNET_OS_PROCESS_UNKNOWN;
1749 statusCode = 0;
1750 }
1751 if ((GNUNET_OS_PROCESS_EXITED == statusType) ||
1752 (GNUNET_OS_PROCESS_SIGNALED == statusType))
1753 {
1754 double utime = ru.ru_utime.tv_sec + (ru.ru_utime.tv_usec / 10e6);
1755 double stime = ru.ru_stime.tv_sec + (ru.ru_stime.tv_usec / 10e6);
1756 fprintf (wait_file,
1757 "%s(%u) %.3f %.3f %llu %llu %llu %llu %llu\n",
1758 pos->binary,
1759 (unsigned int) pid,
1760 utime,
1761 stime,
1762 (unsigned long long) ru.ru_maxrss,
1763 (unsigned long long) ru.ru_inblock,
1764 (unsigned long long) ru.ru_oublock,
1765 (unsigned long long) ru.ru_nvcsw,
1766 (unsigned long long) ru.ru_nivcsw);
1767 }
1768 }
1769 else /* continue with JUST this "if" as "else" (intentionally no brackets!) */
1770#endif
1772 &statusType,
1773 &statusCode))) ||
1774 (ret == GNUNET_NO) || (statusType == GNUNET_OS_PROCESS_STOPPED) ||
1775 (statusType == GNUNET_OS_PROCESS_UNKNOWN) ||
1776 (statusType == GNUNET_OS_PROCESS_RUNNING))
1777 continue;
1778
1779 if (statusType == GNUNET_OS_PROCESS_EXITED)
1780 {
1781 statstr = _ (/* process termination method */ "exit");
1782 statcode = statusCode;
1783 }
1784 else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
1785 {
1786 statstr = _ (/* process termination method */ "signal");
1787 statcode = statusCode;
1788 }
1789 else
1790 {
1791 statstr = _ (/* process termination method */ "unknown");
1792 statcode = 0;
1793 }
1794 if (0 != pos->killed_at.abs_value_us)
1795 {
1797 _ ("Service `%s' took %s to terminate\n"),
1798 pos->name,
1801 GNUNET_YES));
1802 }
1804 pos->proc = NULL;
1806 if (NULL != pos->killing_client)
1807 {
1809 pos->name,
1812 pos->killing_client = NULL;
1814 }
1815 if (GNUNET_YES != in_shutdown)
1816 {
1817 pos->last_exit_status = statcode;
1818 if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0))
1819 {
1820 /* process terminated normally, allow restart at any time */
1821 pos->restart_at.abs_value_us = 0;
1822 GNUNET_log (
1824 _ ("Service `%s' terminated normally, will restart at any time\n"),
1825 pos->name);
1826 /* process can still be re-started on-demand, ensure it is re-started if there is demand */
1827 for (sli = pos->listen_head; NULL != sli; sli = sli->next)
1828 {
1829 GNUNET_break (NULL == sli->accept_task);
1830 sli->accept_task =
1832 sli->listen_socket,
1834 sli);
1835 }
1836 }
1837 else
1838 {
1839 GNUNET_log (
1841 _ ("Service `%s' terminated with status %s/%d, will restart in %s\n"),
1842 pos->name,
1843 statstr,
1844 statcode,
1846 {
1847 /* Reduce backoff based on runtime of the process,
1848 so that there is a cool-down if a process actually
1849 runs for a while. */
1850 struct GNUNET_TIME_Relative runtime;
1851 unsigned int minutes;
1852
1854 minutes =
1855 runtime.rel_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us;
1856 if (minutes > 31)
1858 else
1859 pos->backoff.rel_value_us >>= minutes;
1860 }
1861 /* schedule restart */
1864 if (NULL != child_restart_task)
1869 NULL);
1870 }
1871 }
1872 else
1873 {
1874 free_service (pos);
1875 }
1876 }
1879 pr,
1881 NULL);
1882 if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
1883 do_shutdown ();
1884 else if (GNUNET_YES == in_shutdown)
1886 "Delaying shutdown after child's death, still have %u children\n",
1888}
1889
1890
1895static void
1897{
1898 static char c;
1899 int old_errno = errno; /* back-up errno */
1900
1901 GNUNET_break (
1902 1 ==
1905 ,
1906 &c,
1907 sizeof(c)));
1908 errno = old_errno; /* restore errno */
1909}
1910
1911
1920static void
1921setup_service (void *cls, const char *section)
1922{
1923 struct ServiceList *sl;
1924 char *binary;
1925 char *config;
1926 struct stat sbuf;
1927 struct sockaddr **addrs;
1928 socklen_t *addr_lens;
1929 int ret;
1930
1931 (void) cls;
1932 if (0 == strcasecmp (section, "arm"))
1933 return;
1934 if (GNUNET_OK !=
1935 GNUNET_CONFIGURATION_get_value_string (cfg, section, "BINARY", &binary))
1936 {
1937 /* not a service section */
1938 return;
1939 }
1940 if (GNUNET_YES ==
1942 section,
1943 "RUN_PER_USER"))
1944 {
1945 if (GNUNET_NO == start_user)
1946 {
1947 GNUNET_free (binary);
1948 return; /* user service, and we don't deal with those */
1949 }
1950 }
1951 else
1952 {
1953 if (GNUNET_NO == start_system)
1954 {
1955 GNUNET_free (binary);
1956 return; /* system service, and we don't deal with those */
1957 }
1958 }
1959 sl = find_service (section);
1960 if (NULL != sl)
1961 {
1962 /* got the same section twice!? */
1963 GNUNET_break (0);
1964 GNUNET_free (binary);
1965 return;
1966 }
1967 config = NULL;
1968 if (((GNUNET_OK !=
1970 section,
1971 "CONFIG",
1972 &config)) &&
1973 (GNUNET_OK !=
1975 "PATHS",
1976 "DEFAULTCONFIG",
1977 &config))) ||
1978 (0 != stat (config,
1979 &sbuf)))
1980 {
1981 if (NULL != config)
1982 {
1984 section,
1985 "CONFIG",
1986 strerror (errno));
1988 config = NULL;
1989 }
1990 }
1991 sl = GNUNET_new (struct ServiceList);
1992 sl->name = GNUNET_strdup (section);
1993 sl->binary = binary;
1994 sl->config = config;
1997 sl->pipe_control =
1998 (GNUNET_YES ==
2000 section,
2001 "PIPECONTROL"));
2004 sl);
2005 if (GNUNET_YES ==
2007 section,
2008 "IMMEDIATE_START"))
2009 {
2010 sl->force_start = GNUNET_YES;
2011 if (GNUNET_YES ==
2013 section,
2014 "NOARMBIND"))
2015 return;
2016 }
2017 else
2018 {
2019 if (GNUNET_YES !=
2021 section,
2022 "START_ON_DEMAND"))
2023 return;
2024 }
2025 if (0 >= (ret = get_server_addresses (section,
2026 cfg,
2027 &addrs,
2028 &addr_lens)))
2029 return;
2030 /* this will free (or capture) addrs[i] */
2031 for (unsigned int i = 0; i < (unsigned int) ret; i++)
2032 create_listen_socket (addrs[i], addr_lens[i], sl);
2033 GNUNET_free (addrs);
2034 GNUNET_free (addr_lens);
2035}
2036
2037
2046static void *
2047client_connect_cb (void *cls,
2048 struct GNUNET_SERVICE_Client *client,
2049 struct GNUNET_MQ_Handle *mq)
2050{
2051 /* All clients are considered to be of the "monitor" kind
2052 * (that is, they don't affect ARM shutdown).
2053 */
2054 (void) cls;
2055 (void) mq;
2057 return client;
2058}
2059
2060
2068static void
2069client_disconnect_cb (void *cls,
2070 struct GNUNET_SERVICE_Client *client,
2071 void *app_ctx)
2072{
2073 (void) cls;
2074 GNUNET_assert (client == app_ctx);
2075 for (struct ServiceList *sl = running_head; NULL != sl; sl = sl->next)
2076 if (sl->killing_client == client)
2077 sl->killing_client = NULL;
2078}
2079
2080
2089static void
2090handle_monitor (void *cls, const struct GNUNET_MessageHeader *message)
2091{
2092 struct GNUNET_SERVICE_Client *client = cls;
2093
2094 (void) message;
2095 /* FIXME: might want to start by letting monitor know about
2096 services that are already running */
2097 /* Removal is handled by the server implementation, internally. */
2102}
2103
2104
2112static void
2113run (void *cls,
2114 const struct GNUNET_CONFIGURATION_Handle *c,
2115 struct GNUNET_SERVICE_Handle *serv)
2116{
2117 struct ServiceList *sl;
2118 enum GNUNET_GenericReturnValue ret1;
2119 enum GNUNET_GenericReturnValue ret2;
2120
2121 (void) cls;
2122 cfg = c;
2123 service = serv;
2130 NULL);
2131#if HAVE_WAIT4
2132 if (GNUNET_OK ==
2134 "ARM",
2135 "RESOURCE_DIAGNOSTICS",
2136 &wait_filename))
2137 {
2138 wait_file = fopen (wait_filename, "w");
2139 if (NULL == wait_file)
2140 {
2142 "fopen",
2143 wait_filename);
2144 }
2145 }
2146#endif
2147 if (GNUNET_OK !=
2149 "ARM",
2150 "GLOBAL_PREFIX",
2153 else
2155 if (GNUNET_OK !=
2157 "ARM",
2158 "GLOBAL_POSTFIX",
2159 &final_option))
2161 else
2164 "ARM",
2165 "START_SYSTEM_SERVICES");
2167 "ARM",
2168 "START_USER_SERVICES");
2169 if ( (GNUNET_SYSERR == ret1) ||
2170 (GNUNET_SYSERR == ret2) )
2171 {
2172 /* invalid option */
2173 GNUNET_break (0);
2175 global_ret = 1;
2176 return;
2177 }
2179 "ARM",
2180 "START_SYSTEM_SERVICES"))
2181 ret1 = GNUNET_SYSERR;
2183 "ARM",
2184 "START_USER_SERVICES"))
2185 ret2 = GNUNET_SYSERR;
2186 start_system = (GNUNET_YES == ret1) ||
2187 ( (GNUNET_SYSERR == ret1) && (GNUNET_SYSERR == ret2) );
2188 start_user = (GNUNET_YES == ret2) ||
2189 ( (GNUNET_SYSERR == ret1) && (GNUNET_SYSERR == ret2) );
2190 if ( (GNUNET_NO == start_user) &&
2191 (GNUNET_NO == start_system) )
2192 {
2193 GNUNET_log (
2195 "Please enable either START_USER_SERVICES or START_SYSTEM_SERVICES\n");
2197 global_ret = 1;
2198 return;
2199 }
2202 NULL);
2203
2204 /* start default services... */
2205 for (sl = running_head; NULL != sl; sl = sl->next)
2206 if (GNUNET_YES == sl->force_start)
2207 start_process (sl, NULL, 0);
2209}
2210
2211
2219int
2220main (int argc, char *const *argv)
2221{
2226 struct GNUNET_ARM_Message,
2227 NULL),
2230 struct GNUNET_ARM_Message,
2231 NULL),
2234 struct GNUNET_MessageHeader,
2235 NULL),
2238 struct GNUNET_ARM_Message,
2239 NULL),
2242 struct GNUNET_MessageHeader,
2243 NULL),
2245 };
2246
2248 GNUNET_assert (NULL != sigpipe);
2249 shc_chld =
2253 argc,
2254 argv,
2255 "arm",
2258 &run,
2261 NULL,
2262 handlers))
2263 global_ret = 2;
2264#if HAVE_WAIT4
2265 if (NULL != wait_file)
2266 {
2267 fclose (wait_file);
2268 wait_file = NULL;
2269 }
2270 if (NULL != wait_filename)
2271 {
2272 GNUNET_free (wait_filename);
2273 wait_filename = NULL;
2274 }
2275#endif
2277 shc_chld = NULL;
2279 sigpipe = NULL;
2280 return global_ret;
2281}
2282
2283
2284#if defined(__linux__) && defined(__GLIBC__)
2285#include <malloc.h>
2286
2287void __attribute__ ((constructor))
2288GNUNET_ARM_memory_init (void);
2289
2293void __attribute__ ((constructor))
2294GNUNET_ARM_memory_init (void)
2295{
2296 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2297 mallopt (M_TOP_PAD, 1 * 1024);
2298 malloc_trim (0);
2299}
2300
2301
2302#endif
2303
2304
2305/* end of gnunet-service-arm.c */
struct GNUNET_GETOPT_CommandLineOption options[]
Definition 002.c:5
struct GNUNET_MQ_MessageHandlers handlers[]
Definition 003.c:1
struct GNUNET_MessageHeader * msg
Definition 005.c:2
struct GNUNET_MQ_Envelope * env
Definition 005.c:1
static struct GNUNET_SIGNAL_Context * shc_chld
int main()
Program to simulate results from GCP_get_desirability_of_path() for various plausible inputs.
static int start
Set if we are to start default services (including ARM).
Definition gnunet-arm.c:38
static int monitor
Monitor ARM activity.
Definition gnunet-arm.c:63
static int list
Set if we should print a list of currently running services.
Definition gnunet-arm.c:68
static int ret
Final status code.
Definition gnunet-arm.c:93
static uint16_t port
Port number.
Definition gnunet-bcd.c:146
const struct GNUNET_CONFIGURATION_Handle * config
struct GNUNET_SCHEDULER_Task * shutdown_task
static char * name
Name (label) of the records to list.
static char * res
Currently read line or NULL on EOF.
static struct GNUNET_NETWORK_Handle * ls
Listen socket for STUN processing.
Definition gnunet-nat.c:85
static int status
The program status; 0 for success.
Definition gnunet-nse.c:39
static void start_process()
static int result
Global testing status.
static struct GNUNET_SCHEDULER_Task * child_restart_task
ID of task called whenever the timeout for restarting a child expires.
static void delayed_restart_task(void *cls)
Task run whenever it is time to restart a child that died.
static struct ServiceList * running_head
List of running services.
static void trigger_shutdown(void *cls)
Start a shutdown sequence.
static void run(void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *serv)
Process arm requests.
static void broadcast_status(const char *name, enum GNUNET_ARM_ServiceMonitorStatus status, struct GNUNET_SERVICE_Client *unicast)
Tell all clients about status change of a service.
static void free_service(struct ServiceList *sl)
Remove and free an entry in the service list.
#define MAX_NOTIFY_QUEUE
How many messages do we queue up at most for optional notifications to a client? (this can cause noti...
static char * prefix_command
Command to prepend to each actual command.
static void handle_stop(void *cls, const struct GNUNET_ARM_Message *amsg)
Handle STOP-message.
static char * final_option
Option to append to each actual command.
static void add_unixpath(struct sockaddr **saddrs, socklen_t *saddrlens, const char *unixpath, int abstract)
Add the given UNIX domain path as an address to the list (as the first entry).
static int global_ret
Return value from main.
static const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
static int start_user
Are we starting user services?
static void maint_child_death(void *cls)
Task triggered whenever we receive a SIGCHLD (child process died).
static unsigned int list_count(struct ServiceList *run_head)
Count how many services are still active.
static struct GNUNET_SCHEDULER_Task * child_death_task
ID of task called whenever we get a SIGCHILD.
static int start_system
Are we starting system services?
static int check_stop(void *cls, const struct GNUNET_ARM_Message *amsg)
Check STOP-message.
static int in_shutdown
Are we in shutdown mode?
static void handle_test(void *cls, const struct GNUNET_MessageHeader *message)
Handle TEST-message by sending back TEST.
static void setup_service(void *cls, const char *section)
Setup our service record for the given section in the configuration file (assuming the section is for...
static void * client_connect_cb(void *cls, struct GNUNET_SERVICE_Client *client, struct GNUNET_MQ_Handle *mq)
A client connected, mark as a monitoring client.
static struct GNUNET_DISK_PipeHandle * sigpipe
Pipe used to communicate shutdown via signal.
static int get_server_addresses(const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg_, struct sockaddr ***addrs, socklen_t **addr_lens)
Get the list of addresses that a server for the given service should bind to.
static void sighandler_child_death()
Signal handler called for SIGCHLD.
static void accept_connection(void *cls)
First connection has come to the listening socket associated with the service, create the service in ...
static void handle_start(void *cls, const struct GNUNET_ARM_Message *amsg)
Handle START-message.
static void do_shutdown()
We are done with everything.
static struct ServiceList * running_tail
List of running services.
static void handle_list(void *cls, const struct GNUNET_ARM_Message *request)
Handle LIST-message.
static void create_listen_socket(struct sockaddr *sa, socklen_t addr_len, struct ServiceList *sl)
Creating a listening socket for each of the service's addresses and wait for the first incoming conne...
#define LOG(kind,...)
static void handle_monitor(void *cls, const struct GNUNET_MessageHeader *message)
Handle MONITOR-message.
static void signal_result(struct GNUNET_SERVICE_Client *client, const char *name, uint64_t request_id, enum GNUNET_ARM_Result result)
Signal our client that we will start or stop the service.
#define LOG_STRERROR(kind, syscall)
static void client_disconnect_cb(void *cls, struct GNUNET_SERVICE_Client *client, void *app_ctx)
A client disconnected, clean up associated state.
static struct GNUNET_SERVICE_Handle * service
Handle to our service instance.
static struct ServiceList * find_service(const char *name)
Find the process with the given service name in the given list and return it.
static int pool_write(char *pool_start, size_t pool_size, size_t *pool_pos, char *str)
Write a string to a string pool.
static struct GNUNET_NotificationContext * notifier
Context for notifications we need to send to our clients.
static int check_start(void *cls, const struct GNUNET_ARM_Message *amsg)
Check START-message.
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
static char * service_name
Option -s: service name (hash to get service descriptor)
Definition gnunet-vpn.c:50
static struct GNUNET_VPN_RedirectionRequest * request
Opaque redirection request handle.
Definition gnunet-vpn.c:40
struct GNUNET_PQ_ResultSpec __attribute__
GNUNET_ARM_ServiceMonitorStatus
Statuses of services.
GNUNET_ARM_Result
Replies to ARM requests.
@ GNUNET_ARM_SERVICE_STATUS_FINISHED
The service was started, but then exited normally.
@ GNUNET_ARM_SERVICE_STATUS_FAILED
The service has previously failed, and will be restarted.
@ GNUNET_ARM_SERVICE_STATUS_STOPPED
Service is stopped.
@ GNUNET_ARM_SERVICE_STATUS_STOPPING
The service was started, and we're currently waiting for it to be stopped.
@ GNUNET_ARM_SERVICE_STATUS_STARTED
Service has been started and is currently running.
@ GNUNET_ARM_SERVICE_STOPPING
Service stopping was initiated.
@ GNUNET_ARM_SERVICE_STOPPED
Service was stopped.
@ GNUNET_ARM_SERVICE_STARTING
Service starting was initiated.
@ GNUNET_ARM_SERVICE_MONITORING_STARTED
Dummy message.
@ GNUNET_ARM_RESULT_IS_NOT_KNOWN
Asked to start or stop a service, but it's not known.
@ GNUNET_ARM_RESULT_IS_STOPPED_ALREADY
Asked to stop it, but it's already stopped.
@ GNUNET_ARM_RESULT_STARTING
Service starting was initiated.
@ GNUNET_ARM_RESULT_IS_STARTED_ALREADY
Asked to start it, but it's already started.
@ GNUNET_ARM_RESULT_STOPPING
ARM stopping was initiated (there's no "stopped" for ARM itself).
@ GNUNET_ARM_RESULT_IS_STOPPING_ALREADY
Asked to stop it, but it's already stopping.
@ GNUNET_ARM_RESULT_STOPPED
Service was stopped (never sent for ARM itself).
@ GNUNET_ARM_RESULT_START_FAILED
Tried to start a service, but that failed for some reason.
@ GNUNET_ARM_RESULT_IN_SHUTDOWN
Asked to start something, but ARM is shutting down and can't comply.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_filename(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be the name of a file or directory.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_number(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long *number)
Get a configuration value that should be a number.
void GNUNET_CONFIGURATION_iterate_sections(const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_CONFIGURATION_SectionIterator iter, void *iter_cls)
Iterate over all sections in the configuration.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
char * GNUNET_CONFIGURATION_expand_dollar(const struct GNUNET_CONFIGURATION_Handle *cfg, char *orig)
Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR" where either in the "PATHS" section or...
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_have_value(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Test if we have a value for a particular option.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_choice(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, const char *const *choices, const char **value)
Get a configuration value that should be in a set of predefined strings.
const struct GNUNET_DISK_FileHandle * GNUNET_DISK_pipe_handle(const struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd n)
Get the handle to a particular pipe end.
Definition disk.c:1645
void GNUNET_DISK_fix_permissions(const char *fn, int require_uid_match, int require_gid_match)
Update POSIX permissions mask of a file on disk.
Definition disk.c:334
ssize_t GNUNET_DISK_file_write(const struct GNUNET_DISK_FileHandle *h, const void *buffer, size_t n)
Write a buffer to a file.
Definition disk.c:710
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(enum GNUNET_DISK_PipeFlags pf)
Creates an interprocess channel.
Definition disk.c:1468
enum GNUNET_GenericReturnValue GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition disk.c:1615
enum GNUNET_GenericReturnValue GNUNET_DISK_directory_create_for_file(const char *filename)
Create the directory structure for storing a file.
Definition disk.c:633
ssize_t GNUNET_DISK_file_read(const struct GNUNET_DISK_FileHandle *h, void *result, size_t len)
Read the contents of a binary file into a buffer.
Definition disk.c:673
@ GNUNET_DISK_PF_NONE
No special options, use non-blocking read/write operations.
@ GNUNET_DISK_PIPE_END_WRITE
The writing-end of a pipe.
@ GNUNET_DISK_PIPE_END_READ
The reading-end of a pipe.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
#define GNUNET_log(kind,...)
uint64_t GNUNET_ntohll(uint64_t n)
Convert unsigned 64-bit integer to host byte order.
uint64_t GNUNET_htonll(uint64_t n)
Convert unsigned 64-bit integer to network byte order.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
@ GNUNET_SCHEDULER_PRIORITY_IDLE
Run when otherwise idle.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
const char * GNUNET_a2s(const struct sockaddr *addr, socklen_t addrlen)
Convert a "struct sockaddr*" (IPv4 or IPv6 address) to a string (for printing debug messages).
void GNUNET_log_config_invalid(enum GNUNET_ErrorType kind, const char *section, const char *option, const char *required)
Log error message about invalid configuration option value.
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
#define GNUNET_log_strerror_file(level, cmd, filename)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_BULK
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_array_grow(arr, size, tsize)
Grow a well-typed (!) array.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#define GNUNET_array_append(arr, len, element)
Append an element to an array (growing the array by one).
#define GNUNET_free(ptr)
Wrapper around free.
void GNUNET_notification_context_destroy(struct GNUNET_NotificationContext *nc)
Destroy the context, force disconnect for all subscribers.
Definition nc.c:138
void GNUNET_MQ_send(struct GNUNET_MQ_Handle *mq, struct GNUNET_MQ_Envelope *ev)
Send a message with the given message queue.
Definition mq.c:305
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
#define GNUNET_MQ_check_zero_termination(m)
Insert code for a "check_" function that verifies that a given variable-length message received over ...
void GNUNET_MQ_discard(struct GNUNET_MQ_Envelope *mqm)
Discard the message queue message, free all allocated resources.
Definition mq.c:285
#define GNUNET_MQ_msg_extra(mvar, esize, type)
Allocate an envelope, with extra space allocated after the space needed by the message struct.
struct GNUNET_NotificationContext * GNUNET_notification_context_create(unsigned int queue_length)
Create a new notification context.
Definition nc.c:122
void GNUNET_notification_context_broadcast(struct GNUNET_NotificationContext *nc, const struct GNUNET_MessageHeader *msg, int can_drop)
Send a message to all subscribers of this context.
Definition nc.c:190
#define GNUNET_MQ_msg(mvar, type)
Allocate a GNUNET_MQ_Envelope.
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
#define GNUNET_MQ_hd_fixed_size(name, code, str, ctx)
void GNUNET_notification_context_add(struct GNUNET_NotificationContext *nc, struct GNUNET_MQ_Handle *mq)
Add a subscriber to the notification context.
Definition nc.c:161
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition network.c:508
int GNUNET_NETWORK_get_fd(const struct GNUNET_NETWORK_Handle *desc)
Return file descriptor for this network handle.
Definition network.c:1001
char * GNUNET_NETWORK_shorten_unixpath(char *unixpath)
Given a unixpath that is too long (larger than UNIX_PATH_MAX), shorten it to an acceptable length whi...
Definition network.c:143
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create(int domain, int type, int protocol)
Create a new socket.
Definition network.c:833
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_bind(struct GNUNET_NETWORK_Handle *desc, const struct sockaddr *address, socklen_t address_len)
Bind a socket to a particular address.
Definition network.c:439
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_listen(const struct GNUNET_NETWORK_Handle *desc, int backlog)
Listen on a socket.
Definition network.c:652
void GNUNET_NETWORK_unix_precheck(const struct sockaddr_un *un)
If services crash, they can leave a unix domain socket file on the disk.
Definition network.c:178
int GNUNET_NETWORK_socket_setsockopt(struct GNUNET_NETWORK_Handle *fd, int level, int option_name, const void *option_value, socklen_t option_len)
Set socket option.
Definition network.c:806
const struct GNUNET_OS_ProjectData * GNUNET_OS_project_data_gnunet(void)
Return default project data used by 'libgnunetutil' for GNUnet.
struct GNUNET_OS_Process * GNUNET_OS_start_process_s(enum GNUNET_OS_InheritStdioFlags std_inheritance, const int *lsocks, const char *filename,...)
Start a process.
pid_t GNUNET_OS_process_get_pid(struct GNUNET_OS_Process *proc)
Get the pid of the process in question.
GNUNET_OS_ProcessStatusType
Process status types.
void GNUNET_OS_process_destroy(struct GNUNET_OS_Process *proc)
Cleans up process structure contents (OS-dependent) and deallocates it.
int GNUNET_OS_process_kill(struct GNUNET_OS_Process *proc, int sig)
Sends a signal to the process.
enum GNUNET_GenericReturnValue GNUNET_OS_process_status(struct GNUNET_OS_Process *proc, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code)
Retrieve the status of a process.
char * GNUNET_OS_get_libexec_binary_path(const struct GNUNET_OS_ProjectData *pd, const char *progname)
Given the name of a gnunet-helper, gnunet-service or gnunet-daemon binary, try to prefix it with the ...
@ GNUNET_OS_INHERIT_STD_OUT_AND_ERR
When these flags are set, the child process will inherit stdout and stderr of the parent.
@ GNUNET_OS_USE_PIPE_CONTROL
Should a pipe be used to send signals to the child?
@ GNUNET_OS_PROCESS_SIGNALED
The process was killed by a signal.
@ GNUNET_OS_PROCESS_EXITED
The process exited with a return code.
@ GNUNET_OS_PROCESS_UNKNOWN
The process is not known to the OS (or at least not one of our children).
@ GNUNET_OS_PROCESS_STOPPED
The process is paused (but could be resumed).
@ GNUNET_OS_PROCESS_RUNNING
The process is still running.
#define GNUNET_MESSAGE_TYPE_ARM_STOP
Request to ARM to stop a service.
#define GNUNET_MESSAGE_TYPE_ARM_RESULT
Response from ARM.
#define GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT
Response from ARM for listing currently running services.
#define GNUNET_MESSAGE_TYPE_ARM_TEST
Test if ARM service is online.
#define GNUNET_MESSAGE_TYPE_ARM_STATUS
Status update from ARM.
#define GNUNET_MESSAGE_TYPE_ARM_START
Request to ARM to start a service.
#define GNUNET_MESSAGE_TYPE_ARM_LIST
Request to ARM to list all currently running services.
#define GNUNET_MESSAGE_TYPE_ARM_MONITOR
Request to ARM to notify client of service status changes.
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition scheduler.c:567
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_read_net(struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *rfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition scheduler.c:1511
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_read_file(struct GNUNET_TIME_Relative delay, const struct GNUNET_DISK_FileHandle *rfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition scheduler.c:1661
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition scheduler.c:1339
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition scheduler.c:980
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition scheduler.c:1304
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed_with_priority(struct GNUNET_TIME_Relative delay, enum GNUNET_SCHEDULER_Priority priority, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition scheduler.c:1207
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_with_priority(enum GNUNET_SCHEDULER_Priority prio, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified priority.
Definition scheduler.c:1231
void GNUNET_SERVICE_shutdown(struct GNUNET_SERVICE_Handle *sh)
Explicitly stops the service.
Definition service.c:2511
int GNUNET_SERVICE_run_(const struct GNUNET_OS_ProjectData *pd, int argc, char *const *argv, const char *service_name, enum GNUNET_SERVICE_Options options, GNUNET_SERVICE_InitCallback service_init_cb, GNUNET_SERVICE_ConnectHandler connect_cb, GNUNET_SERVICE_DisconnectHandler disconnect_cb, void *cls, const struct GNUNET_MQ_MessageHandler *handlers)
Creates the "main" function for a GNUnet service.
Definition service.c:2021
void GNUNET_SERVICE_client_mark_monitor(struct GNUNET_SERVICE_Client *c)
Set the 'monitor' flag on this client.
Definition service.c:2527
void GNUNET_SERVICE_client_persist(struct GNUNET_SERVICE_Client *c)
Set the persist option on this client.
Definition service.c:2537
struct GNUNET_MQ_Handle * GNUNET_SERVICE_client_get_mq(struct GNUNET_SERVICE_Client *c)
Obtain the message queue of c.
Definition service.c:2544
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition service.c:2433
@ GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN
Do not trigger server shutdown on signal at all; instead, allow for the user to terminate the server ...
@ GNUNET_SERVICE_OPTION_CLOSE_LSOCKS
Instead of listening on lsocks passed by the parent, close them after opening our own listen socket(s...
struct GNUNET_SIGNAL_Context * GNUNET_SIGNAL_handler_install(int signal, GNUNET_SIGNAL_Handler handler)
Install a signal handler that will be run if the given signal is received.
Definition signal.c:52
void GNUNET_SIGNAL_handler_uninstall(struct GNUNET_SIGNAL_Context *ctx)
Uninstall a previously installed signal handler.
Definition signal.c:78
size_t GNUNET_strlcpy(char *dst, const char *src, size_t n)
Like strlcpy but portable.
Definition strings.c:137
struct GNUNET_TIME_Relative GNUNET_TIME_relative_min(struct GNUNET_TIME_Relative t1, struct GNUNET_TIME_Relative t2)
Return the minimum of two relative time values.
Definition time.c:344
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_duration(struct GNUNET_TIME_Absolute whence)
Get the duration of an operation as the difference of the current time and the given start time "henc...
Definition time.c:438
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_remaining(struct GNUNET_TIME_Absolute future)
Given a timestamp in the future, how much time remains until then?
Definition time.c:406
const char * GNUNET_STRINGS_relative_time_to_string(struct GNUNET_TIME_Relative delta, int do_round)
Give relative time in human-readable fancy format.
Definition strings.c:599
#define GNUNET_TIME_UNIT_MILLISECONDS
One millisecond.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition time.c:111
#define GNUNET_TIME_UNIT_MINUTES
One minute.
struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute(struct GNUNET_TIME_Relative rel)
Convert relative time to an absolute time in the future.
Definition time.c:316
#define GNUNET_TIME_UNIT_ZERO
Relative time zero.
struct GNUNET_TIME_AbsoluteNBO GNUNET_TIME_absolute_hton(struct GNUNET_TIME_Absolute a)
Convert absolute time to network byte order.
Definition time.c:640
#define GNUNET_TIME_UNIT_FOREVER_ABS
Constant used to specify "forever".
#define GNUNET_TIME_STD_BACKOFF(r)
Perform our standard exponential back-off calculation, starting at 1 ms and then going by a factor of...
#define _(String)
GNU gettext support macro.
Definition platform.h:179
#define GNUNET_SIGCHLD
Definition platform.h:42
#define GNUNET_TERM_SIG
The termination signal.
Definition platform.h:235
static struct GNUNET_MQ_Handle * mq
Our connection to the resolver service, created on-demand, but then persists until error or shutdown.
Reply from ARM to client for the GNUNET_MESSAGE_TYPE_ARM_LIST request followed by count '\0' terminat...
Definition arm.h:145
uint64_t request_id
ID of a request that is being replied to.
Definition arm.h:77
Reply from ARM to client.
Definition arm.h:87
struct GNUNET_TIME_AbsoluteNBO last_started_at
Time when the service was first started, if applicable.
Definition arm.h:135
uint16_t binary_index
String pool index for the service's binary.
Definition arm.h:109
struct GNUNET_TIME_AbsoluteNBO restart_at
Time when the service will be restarted, if applicable to the current status.
Definition arm.h:130
uint32_t status
Status from the 'enum GNUNET_ARM_ServiceStatus'.
Definition arm.h:124
int16_t last_exit_status
Last process exit status.
Definition arm.h:114
uint16_t name_index
String pool index for the service's name.
Definition arm.h:104
Status update from ARM to client.
Definition arm.h:42
Handle used to access files (and pipes).
Handle used to manage a pipe.
Definition disk.c:69
Handle to a message queue.
Definition mq.c:87
Message handler for a specific message type.
Header for all communications.
handle to a socket
Definition network.c:53
The notification context is the key datastructure for a convenience API used for transmission of noti...
Definition nc.c:77
Entry in list of pending tasks.
Definition scheduler.c:136
Handle to a client that is connected to a service.
Definition service.c:249
Handle to a service.
Definition service.c:116
Time for absolute times used by GNUnet, in microseconds.
uint64_t abs_value_us
The actual value.
Time for relative time used by GNUnet, in microseconds.
uint64_t rel_value_us
The actual value.
uint64_t request_id
non-zero if this request has been sent to the service.
Definition vpn_api.c:127
List of our services.
struct ServiceListeningInfo * listen_head
Linked list of listen sockets associated with this service.
struct ServiceListeningInfo * listen_tail
Linked list of listen sockets associated with this service.
char * binary
Name of the binary used.
int pipe_control
Should we use pipes to signal this process? (YES for Java binaries and if we are on Windoze).
char * config
Name of the configuration file used.
int last_exit_status
Last exit status of the process.
struct ServiceList * next
This is a doubly-linked list.
struct GNUNET_TIME_Absolute last_started_at
Absolute time at which the process was (re-)started last.
struct GNUNET_OS_Process * proc
Process structure pointer of the child.
struct GNUNET_SERVICE_Client * killing_client
Client to notify upon kill completion (waitpid), NULL if we should simply restart the process.
struct GNUNET_TIME_Relative backoff
Process exponential backoff time.
struct ServiceList * prev
This is a doubly-linked list.
char * name
Name of the service.
int force_start
Is this service to be started by default (or did a client tell us explicitly to start it)?...
struct GNUNET_TIME_Absolute killed_at
Time we asked the service to shut down (used to calculate time it took the service to terminate).
struct GNUNET_TIME_Absolute restart_at
Absolute time at which the process is scheduled to restart in case of death.
uint64_t killing_client_request_id
ID of the request that killed the service (for reporting back).
Record with information about a listen socket we have open.
struct ServiceListeningInfo * prev
This is a linked list.
struct ServiceListeningInfo * next
This is a linked list.
struct sockaddr * service_addr
Address this socket is listening on.
struct ServiceList * sl
Service this listen socket is for.
socklen_t service_addr_len
Number of bytes in service_addr.
struct GNUNET_SCHEDULER_Task * accept_task
Task doing the accepting.
struct GNUNET_NETWORK_Handle * listen_socket
Our listening socket.

◆ MAX_NOTIFY_QUEUE

#define MAX_NOTIFY_QUEUE   1024

How many messages do we queue up at most for optional notifications to a client? (this can cause notifications about outgoing messages to be dropped).

Definition at line 56 of file gnunet-service-arm.c.

Function Documentation

◆ add_unixpath()

static void add_unixpath ( struct sockaddr **  saddrs,
socklen_t *  saddrlens,
const char *  unixpath,
int  abstract 
)
static

Add the given UNIX domain path as an address to the list (as the first entry).

Parameters
saddrsarray to update
saddrlenswhere to store the address length
unixpathpath to add
abstractGNUNET_YES to add an abstract UNIX domain socket. This parameter is ignore on systems other than LINUX

Definition at line 293 of file gnunet-service-arm.c.

297{
298#ifdef AF_UNIX
299 struct sockaddr_un *un;
300
301 un = GNUNET_new (struct sockaddr_un);
302 un->sun_family = AF_UNIX;
303 GNUNET_strlcpy (un->sun_path, unixpath, sizeof(un->sun_path));
304#ifdef __linux__
305 if (GNUNET_YES == abstract)
306 un->sun_path[0] = '\0';
307#endif
308#if HAVE_SOCKADDR_UN_SUN_LEN
309 un->sun_len = (u_char) sizeof(struct sockaddr_un);
310#endif
311 *saddrs = (struct sockaddr *) un;
312 *saddrlens = sizeof(struct sockaddr_un);
313#else
314 /* this function should never be called
315 * unless AF_UNIX is defined! */
316 GNUNET_assert (0);
317#endif
318}

References GNUNET_assert, GNUNET_new, GNUNET_strlcpy(), and GNUNET_YES.

Referenced by get_server_addresses().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_server_addresses()

static int get_server_addresses ( const char *  service_name,
const struct GNUNET_CONFIGURATION_Handle cfg_,
struct sockaddr ***  addrs,
socklen_t **  addr_lens 
)
static

Get the list of addresses that a server for the given service should bind to.

Parameters
service_namename of the service
cfgconfiguration (which specifies the addresses)
addrsset (call by reference) to an array of pointers to the addresses the server should bind to and listen on; the array will be NULL-terminated (on success)
addr_lensset (call by reference) to an array of the lengths of the respective struct sockaddr struct in the addrs array (on success)
Returns
number of addresses found on success, GNUNET_SYSERR if the configuration did not specify reasonable finding information or if it specified a hostname that could not be resolved; GNUNET_NO if the number of addresses configured is zero (in this case, *addrs and *addr_lens will be set to NULL).

Definition at line 342 of file gnunet-service-arm.c.

346{
347 int disablev6;
348 struct GNUNET_NETWORK_Handle *desc;
349 unsigned long long port;
350 char *unixpath;
351 struct addrinfo hints;
352 struct addrinfo *res;
353 struct addrinfo *pos;
354 struct addrinfo *next;
355 unsigned int i;
356 int resi;
357 int ret;
358 int abstract;
359 struct sockaddr **saddrs;
360 socklen_t *saddrlens;
361 char *hostname;
362
363 *addrs = NULL;
364 *addr_lens = NULL;
365 desc = NULL;
366 disablev6 = GNUNET_NO;
367 if (GNUNET_SYSERR ==
368 (disablev6 = GNUNET_CONFIGURATION_get_value_yesno (cfg_,
370 "DISABLEV6")))
371 return GNUNET_SYSERR;
372 if (! disablev6)
373 {
374 /* probe IPv6 support */
375 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
376 if (NULL == desc)
377 {
378 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
379 (EACCES == errno))
380 {
382 return GNUNET_SYSERR;
383 }
385 _ (
386 "Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
388 strerror (errno));
389 disablev6 = GNUNET_YES;
390 }
391 else
392 {
394 }
395 }
396
397 port = 0;
399 {
400 if (GNUNET_OK !=
403 "PORT",
404 &port))
405 {
407 _ ("Require valid port number for service `%s' in configuration!\n"),
409 }
410 if (port > 65535)
411 {
413 _ ("Require valid port number for service `%s' in configuration!\n"),
415 return GNUNET_SYSERR;
416 }
417 }
418
419 hostname = NULL;
423 "BINDTO",
424 &hostname));
425 unixpath = NULL;
426 abstract = GNUNET_NO;
427#ifdef AF_UNIX
428 if ( (GNUNET_OK ==
431 "UNIXPATH",
432 &unixpath)) &&
433 (0 < strlen (unixpath)) )
434 {
435 /* probe UNIX support */
436 struct sockaddr_un s_un;
437
438 if (strlen (unixpath) >= sizeof(s_un.sun_path))
439 {
441 _ ("UNIXPATH `%s' too long, maximum length is %llu\n"),
442 unixpath,
443 (unsigned long long) sizeof(s_un.sun_path));
444 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
445 LOG (GNUNET_ERROR_TYPE_INFO, _ ("Using `%s' instead\n"), unixpath);
446 }
447#ifdef __linux__
449 "TESTING",
450 "USE_ABSTRACT_SOCKETS");
451 if (GNUNET_SYSERR == abstract)
452 abstract = GNUNET_NO;
453#endif
454 if ((GNUNET_YES != abstract) &&
457 }
458 if (NULL != unixpath)
459 {
460 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
461 if (NULL == desc)
462 {
463 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
464 (EACCES == errno))
465 {
467 GNUNET_free (hostname);
468 GNUNET_free (unixpath);
469 return GNUNET_SYSERR;
470 }
472 _ (
473 "Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
475 strerror (errno));
476 GNUNET_free (unixpath);
477 unixpath = NULL;
478 }
479 else
480 {
482 desc = NULL;
483 }
484 }
485#endif
486
487 if ((0 == port) && (NULL == unixpath))
488 {
489 if (GNUNET_YES ==
492 "START_ON_DEMAND"))
494 _ (
495 "Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
497 GNUNET_free (hostname);
498 return GNUNET_SYSERR;
499 }
500 if (0 == port)
501 {
502 saddrs = GNUNET_new_array (2, struct sockaddr *);
503 saddrlens = GNUNET_new_array (2, socklen_t);
504 add_unixpath (saddrs, saddrlens, unixpath, abstract);
505 GNUNET_free (unixpath);
506 GNUNET_free (hostname);
507 *addrs = saddrs;
508 *addr_lens = saddrlens;
509 return 1;
510 }
511
512 if (NULL != hostname)
513 {
515 "Resolving `%s' since that is where `%s' will bind to.\n",
516 hostname,
518 memset (&hints, 0, sizeof(struct addrinfo));
519 if (disablev6)
520 hints.ai_family = AF_INET;
521 hints.ai_protocol = IPPROTO_TCP;
522 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
523 (NULL == res))
524 {
526 _ ("Failed to resolve `%s': %s\n"),
527 hostname,
528 gai_strerror (ret));
529 GNUNET_free (hostname);
530 GNUNET_free (unixpath);
531 return GNUNET_SYSERR;
532 }
533 next = res;
534 i = 0;
535 while (NULL != (pos = next))
536 {
537 next = pos->ai_next;
538 if ((disablev6) && (pos->ai_family == AF_INET6))
539 continue;
540 i++;
541 }
542 if (0 == i)
543 {
545 _ ("Failed to find %saddress for `%s'.\n"),
546 disablev6 ? "IPv4 " : "",
547 hostname);
548 freeaddrinfo (res);
549 GNUNET_free (hostname);
550 GNUNET_free (unixpath);
551 return GNUNET_SYSERR;
552 }
553 resi = i;
554 if (NULL != unixpath)
555 resi++;
556 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
557 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
558 i = 0;
559 if (NULL != unixpath)
560 {
561 add_unixpath (saddrs, saddrlens, unixpath, abstract);
562 i++;
563 }
564 next = res;
565 while (NULL != (pos = next))
566 {
567 next = pos->ai_next;
568 if ((disablev6) && (AF_INET6 == pos->ai_family))
569 continue;
570 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
571 continue; /* not TCP */
572 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
573 continue; /* huh? */
575 "Service `%s' will bind to `%s'\n",
577 GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
578 if (AF_INET == pos->ai_family)
579 {
580 GNUNET_assert (sizeof(struct sockaddr_in) == pos->ai_addrlen);
581 saddrlens[i] = pos->ai_addrlen;
582 saddrs[i] = GNUNET_malloc (saddrlens[i]);
583 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
584 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
585 }
586 else
587 {
588 GNUNET_assert (AF_INET6 == pos->ai_family);
589 GNUNET_assert (sizeof(struct sockaddr_in6) == pos->ai_addrlen);
590 saddrlens[i] = pos->ai_addrlen;
591 saddrs[i] = GNUNET_malloc (saddrlens[i]);
592 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
593 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
594 }
595 i++;
596 }
597 GNUNET_free (hostname);
598 freeaddrinfo (res);
599 resi = i;
600 }
601 else
602 {
603 /* will bind against everything, just set port */
604 if (disablev6)
605 {
606 /* V4-only */
607 resi = 1;
608 if (NULL != unixpath)
609 resi++;
610 i = 0;
611 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
612 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
613 if (NULL != unixpath)
614 {
615 add_unixpath (saddrs, saddrlens, unixpath, abstract);
616 i++;
617 }
618 saddrlens[i] = sizeof(struct sockaddr_in);
619 saddrs[i] = GNUNET_malloc (saddrlens[i]);
620#if HAVE_SOCKADDR_IN_SIN_LEN
621 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
622#endif
623 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
624 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
625 }
626 else
627 {
628 /* dual stack */
629 resi = 2;
630 if (NULL != unixpath)
631 resi++;
632 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
633 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
634 i = 0;
635 if (NULL != unixpath)
636 {
637 add_unixpath (saddrs, saddrlens, unixpath, abstract);
638 i++;
639 }
640 saddrlens[i] = sizeof(struct sockaddr_in6);
641 saddrs[i] = GNUNET_malloc (saddrlens[i]);
642#if HAVE_SOCKADDR_IN_SIN_LEN
643 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
644#endif
645 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
646 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
647 i++;
648 saddrlens[i] = sizeof(struct sockaddr_in);
649 saddrs[i] = GNUNET_malloc (saddrlens[i]);
650#if HAVE_SOCKADDR_IN_SIN_LEN
651 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
652#endif
653 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
654 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
655 }
656 }
657 GNUNET_free (unixpath);
658 *addrs = saddrs;
659 *addr_lens = saddrlens;
660 return resi;
661}

References _, add_unixpath(), cfg, GNUNET_a2s(), GNUNET_assert, GNUNET_break, GNUNET_CONFIGURATION_get_value_filename(), GNUNET_CONFIGURATION_get_value_number(), GNUNET_CONFIGURATION_get_value_string(), GNUNET_CONFIGURATION_get_value_yesno(), GNUNET_CONFIGURATION_have_value(), GNUNET_DISK_directory_create_for_file(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_INFO, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_log_strerror_file, GNUNET_malloc, GNUNET_memcpy, GNUNET_NETWORK_shorten_unixpath(), GNUNET_NETWORK_socket_close(), GNUNET_NETWORK_socket_create(), GNUNET_new_array, GNUNET_NO, GNUNET_OK, GNUNET_SYSERR, GNUNET_YES, LOG, LOG_STRERROR, port, res, ret, and service_name.

Referenced by setup_service().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ signal_result()

static void signal_result ( struct GNUNET_SERVICE_Client client,
const char *  name,
uint64_t  request_id,
enum GNUNET_ARM_Result  result 
)
static

Signal our client that we will start or stop the service.

Parameters
clientwho is being signalled
namename of the service
request_idid of the request that is being responded to.
resultmessage type to send
Returns
NULL if it was not found

Definition at line 675 of file gnunet-service-arm.c.

679{
680 struct GNUNET_MQ_Envelope *env;
682
683 (void) name;
685 msg->result = htonl (result);
686 msg->arm_msg.request_id = GNUNET_htonll (request_id);
688}

References env, GNUNET_htonll(), GNUNET_MESSAGE_TYPE_ARM_RESULT, GNUNET_MQ_msg, GNUNET_MQ_send(), GNUNET_SERVICE_client_get_mq(), msg, name, and result.

Referenced by handle_start(), handle_stop(), maint_child_death(), and start_process().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ broadcast_status()

static void broadcast_status ( const char *  name,
enum GNUNET_ARM_ServiceMonitorStatus  status,
struct GNUNET_SERVICE_Client unicast 
)
static

Tell all clients about status change of a service.

Parameters
namename of the service
statusmessage type to send
unicastif not NULL, send to this client only. otherwise, send to all clients in the notifier

Definition at line 700 of file gnunet-service-arm.c.

703{
704 struct GNUNET_MQ_Envelope *env;
706 size_t namelen;
707
709 "Sending status %u of service `%s' to client\n",
710 (unsigned int) status,
711 name);
712 namelen = strlen (name) + 1;
714 namelen,
716 msg->status = htonl ((uint32_t) (status));
717 GNUNET_memcpy ((char *) &msg[1],
718 name,
719 namelen);
720 if (NULL == unicast)
721 {
722 if (NULL != notifier)
724 &msg->header,
725 GNUNET_YES);
727 }
728 else
729 {
731 env);
732 }
733}

References env, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_memcpy, GNUNET_MESSAGE_TYPE_ARM_STATUS, GNUNET_MQ_discard(), GNUNET_MQ_msg_extra, GNUNET_MQ_send(), GNUNET_notification_context_broadcast(), GNUNET_SERVICE_client_get_mq(), GNUNET_YES, msg, name, notifier, and status.

Referenced by handle_monitor(), handle_stop(), maint_child_death(), and start_process().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ start_process()

static void start_process ( struct ServiceList sl,
struct GNUNET_SERVICE_Client client,
uint64_t  request_id 
)
static

Actually start the process for the given service.

Parameters
slidentifies service to start
clientthat asked to start the service (may be NULL)
request_idid of the request in response to which the process is being started. 0 if starting was not requested.

Definition at line 745 of file gnunet-service-arm.c.

748{
749 char *loprefix;
750 char *options;
751 enum GNUNET_GenericReturnValue use_debug;
752 bool is_simple_service;
753 int *lsocks;
754 unsigned int ls;
755 char *binary;
756 char *quotedbinary;
757
758 /* calculate listen socket list */
759 lsocks = NULL;
760 ls = 0;
761 for (struct ServiceListeningInfo *sli = sl->listen_head;
762 NULL != sli;
763 sli = sli->next)
764 {
765 GNUNET_array_append (lsocks,
766 ls,
767 GNUNET_NETWORK_get_fd (sli->listen_socket));
768 if (NULL != sli->accept_task)
769 {
770 GNUNET_SCHEDULER_cancel (sli->accept_task);
771 sli->accept_task = NULL;
772 }
773 }
774
775 GNUNET_array_append (lsocks,
776 ls,
777 -1);
778
779 /* obtain configuration */
780 if (GNUNET_OK !=
782 sl->name,
783 "PREFIX",
784 &loprefix))
785 loprefix = GNUNET_strdup (prefix_command);
786 else
788 loprefix);
789 if (GNUNET_OK !=
791 sl->name,
792 "OPTIONS",
793 &options))
794 options = NULL;
795 else
797 {
798 char *new_options;
799 char *optpos;
800 char *fin_options;
801
802 fin_options = GNUNET_strdup (final_option);
803 /* replace '{}' with service name */
804 while (NULL != (optpos = strstr (fin_options, "{}")))
805 {
806 /* terminate string at opening parenthesis */
807 *optpos = 0;
808 GNUNET_asprintf (&new_options,
809 "%s%s%s",
810 fin_options,
811 sl->name,
812 optpos + 2);
813 GNUNET_free (fin_options);
814 fin_options = new_options;
815 }
816 if (NULL != options)
817 {
818 /* combine "fin_options" with "options" */
819 optpos = options;
820 GNUNET_asprintf (&options, "%s %s", fin_options, optpos);
821 GNUNET_free (fin_options);
822 GNUNET_free (optpos);
823 }
824 else
825 {
826 /* only have "fin_options", use that */
827 options = fin_options;
828 }
829 }
831 options);
833 sl->name,
834 "DEBUG");
835 {
836 const char *service_type = NULL;
837 const char *choices[] = {
838 "GNUNET",
839 "SIMPLE",
840 NULL
841 };
842
843 is_simple_service = false;
844 if ( (GNUNET_OK ==
846 sl->name,
847 "TYPE",
848 choices,
849 &service_type)) &&
850 (0 == strcasecmp (service_type,
851 "SIMPLE")))
852 is_simple_service = true;
853 }
854
855 GNUNET_assert (NULL == sl->proc);
856 if (is_simple_service)
857 {
858 /* A simple service will receive no GNUnet specific
859 command line options. */
860 binary = GNUNET_strdup (sl->binary);
862 binary);
863 GNUNET_asprintf (&quotedbinary,
864 "\"%s\"",
865 sl->binary);
867 "Starting simple service `%s' using binary `%s'\n",
868 sl->name,
869 sl->binary);
870 /* FIXME: dollar expansion should only be done outside
871 * of ''-quoted strings, escaping should be considered. */
872 if (NULL != options)
874 options);
879 lsocks,
880 loprefix,
881 quotedbinary,
882 options,
883 NULL);
884 }
885 else
886 {
887 /* actually start process */
889 "Starting service `%s' using binary `%s' and configuration `%s'\n",
890 sl->name,
891 sl->binary,
892 sl->config);
894 ,
895 sl->binary);
896 GNUNET_asprintf (&quotedbinary,
897 "\"%s\"",
898 binary);
899
900 if (GNUNET_YES == use_debug)
901 {
902 if (NULL == sl->config)
904 sl->pipe_control
908 lsocks,
909 loprefix,
910 quotedbinary,
911 "-L",
912 "DEBUG",
913 options,
914 NULL);
915 else
917 sl->pipe_control
921 lsocks,
922 loprefix,
923 quotedbinary,
924 "-c",
925 sl->config,
926 "-L",
927 "DEBUG",
928 options,
929 NULL);
930 }
931 else
932 {
933 if (NULL == sl->config)
935 sl->pipe_control
939 lsocks,
940 loprefix,
941 quotedbinary,
942 options,
943 NULL);
944 else
946 sl->pipe_control
950 lsocks,
951 loprefix,
952 quotedbinary,
953 "-c",
954 sl->config,
955 options,
956 NULL);
957 }
958 }
959 GNUNET_free (binary);
960 GNUNET_free (quotedbinary);
962 if (NULL == sl->proc)
963 {
965 "Failed to start service `%s'\n",
966 sl->name);
967 if (client)
968 signal_result (client,
969 sl->name,
970 request_id,
972 }
973 else
974 {
976 "Starting service `%s'\n",
977 sl->name);
980 NULL);
981 if (client)
982 signal_result (client,
983 sl->name,
984 request_id,
986 }
987 /* clean up */
988 GNUNET_free (loprefix);
990 GNUNET_array_grow (lsocks,
991 ls,
992 0);
993}

References ServiceList::binary, broadcast_status(), cfg, ServiceList::config, final_option, GNUNET_ARM_RESULT_START_FAILED, GNUNET_ARM_RESULT_STARTING, GNUNET_ARM_SERVICE_STARTING, GNUNET_array_append, GNUNET_array_grow, GNUNET_asprintf(), GNUNET_assert, GNUNET_CONFIGURATION_expand_dollar(), GNUNET_CONFIGURATION_get_value_choice(), GNUNET_CONFIGURATION_get_value_string(), GNUNET_CONFIGURATION_get_value_yesno(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_INFO, GNUNET_free, GNUNET_log, GNUNET_NETWORK_get_fd(), GNUNET_OK, GNUNET_OS_get_libexec_binary_path(), GNUNET_OS_INHERIT_STD_OUT_AND_ERR, GNUNET_OS_project_data_gnunet(), GNUNET_OS_start_process_s(), GNUNET_OS_USE_PIPE_CONTROL, GNUNET_SCHEDULER_cancel(), GNUNET_strdup, GNUNET_TIME_absolute_get(), GNUNET_YES, ServiceList::last_started_at, ServiceList::listen_head, ls, ServiceList::name, options, ServiceList::pipe_control, prefix_command, ServiceList::proc, and signal_result().

Here is the call graph for this function:

◆ find_service()

static struct ServiceList * find_service ( const char *  name)
static

Find the process with the given service name in the given list and return it.

Parameters
namewhich service entry to look up
Returns
NULL if it was not found

Definition at line 1004 of file gnunet-service-arm.c.

1005{
1006 struct ServiceList *sl;
1007
1008 sl = running_head;
1009 while (sl != NULL)
1010 {
1011 if (0 == strcasecmp (sl->name, name))
1012 return sl;
1013 sl = sl->next;
1014 }
1015 return NULL;
1016}

References name, ServiceList::name, ServiceList::next, and running_head.

Referenced by handle_start(), handle_stop(), and setup_service().

Here is the caller graph for this function:

◆ accept_connection()

static void accept_connection ( void *  cls)
static

First connection has come to the listening socket associated with the service, create the service in order to relay the incoming connection to it.

Parameters
clscallback data, struct ServiceListeningInfo describing a listen socket

Definition at line 1026 of file gnunet-service-arm.c.

1027{
1028 struct ServiceListeningInfo *sli = cls;
1029 struct ServiceList *sl = sli->sl;
1030
1031 sli->accept_task = NULL;
1033 start_process (sl, NULL, 0);
1034}

References ServiceListeningInfo::accept_task, GNUNET_assert, GNUNET_NO, in_shutdown, ServiceListeningInfo::sl, and start_process().

Referenced by create_listen_socket(), delayed_restart_task(), and maint_child_death().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_listen_socket()

static void create_listen_socket ( struct sockaddr *  sa,
socklen_t  addr_len,
struct ServiceList sl 
)
static

Creating a listening socket for each of the service's addresses and wait for the first incoming connection to it.

Parameters
saaddress associated with the service
addr_lenlength of sa
slservice entry for the service in question

Definition at line 1046 of file gnunet-service-arm.c.

1049{
1050 static int on = 1;
1051 struct GNUNET_NETWORK_Handle *sock;
1052 struct ServiceListeningInfo *sli;
1053
1054 int match_uid;
1055 int match_gid;
1056
1057 switch (sa->sa_family)
1058 {
1059 case AF_INET:
1060 sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
1061 break;
1062
1063 case AF_INET6:
1064 sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1065 break;
1066
1067 case AF_UNIX:
1068 if (0 == strcmp (GNUNET_a2s (sa, addr_len),
1069 "@")) /* Do not bind to blank UNIX path! */
1070 return;
1071 sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
1072 break;
1073
1074 default:
1075 GNUNET_break (0);
1076 sock = NULL;
1077 errno = EAFNOSUPPORT;
1078 break;
1079 }
1080 if (NULL == sock)
1081 {
1083 _ ("Unable to create socket for service `%s': %s\n"),
1084 sl->name,
1085 strerror (errno));
1086 GNUNET_free (sa);
1087 return;
1088 }
1090 SOL_SOCKET,
1091 SO_REUSEADDR,
1092 &on,
1093 sizeof(on)))
1095 "setsockopt");
1096#ifdef IPV6_V6ONLY
1097 if ((sa->sa_family == AF_INET6) &&
1099 IPPROTO_IPV6,
1100 IPV6_V6ONLY,
1101 &on,
1102 sizeof(on))))
1104 "setsockopt");
1105#endif
1106 if (AF_UNIX == sa->sa_family)
1107 GNUNET_NETWORK_unix_precheck ((struct sockaddr_un *) sa);
1108 if (GNUNET_OK !=
1109 GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) sa, addr_len))
1110 {
1111 GNUNET_log (
1113 _ (
1114 "Unable to bind listening socket for service `%s' to address `%s': %s\n"),
1115 sl->name,
1116 GNUNET_a2s (sa, addr_len),
1117 strerror (errno));
1119 GNUNET_free (sa);
1120 return;
1121 }
1122 if ((AF_UNIX == sa->sa_family)
1123#ifdef __linux__
1124 /* Permission settings are not required when abstract sockets are used */
1125 && ('\0' != ((const struct sockaddr_un *) sa)->sun_path[0])
1126#endif
1127 )
1128 {
1129 match_uid =
1130 (GNUNET_YES ==
1132 sl->name,
1133 "UNIX_MATCH_UID"));
1134 match_gid =
1135 (GNUNET_YES ==
1137 sl->name,
1138 "UNIX_MATCH_GID"));
1139 GNUNET_DISK_fix_permissions (((const struct sockaddr_un *) sa)->sun_path,
1140 match_uid,
1141 match_gid);
1142 }
1143 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
1144 {
1147 GNUNET_free (sa);
1148 return;
1149 }
1151 _ ("ARM now monitors connections to service `%s' at `%s'\n"),
1152 sl->name,
1153 GNUNET_a2s (sa, addr_len));
1154 sli = GNUNET_new (struct ServiceListeningInfo);
1155 sli->service_addr = sa;
1156 sli->service_addr_len = addr_len;
1157 sli->listen_socket = sock;
1158 sli->sl = sl;
1159 sli->accept_task =
1161 sock,
1163 sli);
1165}

References _, accept_connection(), ServiceListeningInfo::accept_task, cfg, GNUNET_a2s(), GNUNET_break, GNUNET_CONFIGURATION_get_value_yesno(), GNUNET_CONTAINER_DLL_insert, GNUNET_DISK_fix_permissions(), GNUNET_ERROR_TYPE_BULK, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_log, GNUNET_log_strerror, GNUNET_NETWORK_socket_bind(), GNUNET_NETWORK_socket_close(), GNUNET_NETWORK_socket_create(), GNUNET_NETWORK_socket_listen(), GNUNET_NETWORK_socket_setsockopt(), GNUNET_NETWORK_unix_precheck(), GNUNET_new, GNUNET_OK, GNUNET_SCHEDULER_add_read_net(), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, ServiceList::listen_head, ServiceListeningInfo::listen_socket, ServiceList::listen_tail, ServiceList::name, ServiceListeningInfo::service_addr, ServiceListeningInfo::service_addr_len, and ServiceListeningInfo::sl.

Referenced by setup_service().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_service()

static void free_service ( struct ServiceList sl)
static

Remove and free an entry in the service list.

Listen sockets must have already been cleaned up. Only to be called during shutdown.

Parameters
slentry to free

Definition at line 1175 of file gnunet-service-arm.c.

1176{
1179 GNUNET_assert (NULL == sl->listen_head);
1180 GNUNET_free (sl->config);
1181 GNUNET_free (sl->binary);
1182 GNUNET_free (sl->name);
1183 GNUNET_free (sl);
1184}

References ServiceList::binary, ServiceList::config, GNUNET_assert, GNUNET_CONTAINER_DLL_remove, GNUNET_free, GNUNET_YES, in_shutdown, ServiceList::listen_head, ServiceList::name, running_head, running_tail, and ServiceListeningInfo::sl.

Referenced by maint_child_death(), and shutdown_task().

Here is the caller graph for this function:

◆ check_start()

static int check_start ( void *  cls,
const struct GNUNET_ARM_Message amsg 
)
static

Check START-message.

Parameters
clsidentification of the client
amsgthe actual message
Returns
GNUNET_OK to keep the connection open, GNUNET_SYSERR to close it (signal serious error)

Definition at line 1196 of file gnunet-service-arm.c.

1197{
1198 (void) cls;
1200 return GNUNET_OK;
1201}

References GNUNET_MQ_check_zero_termination, and GNUNET_OK.

◆ handle_start()

static void handle_start ( void *  cls,
const struct GNUNET_ARM_Message amsg 
)
static

Handle START-message.

Parameters
clsidentification of the client
amsgthe actual message

Definition at line 1211 of file gnunet-service-arm.c.

1212{
1213 struct GNUNET_SERVICE_Client *client = cls;
1214 const char *servicename;
1215 struct ServiceList *sl;
1216 uint64_t request_id;
1217
1218 request_id = GNUNET_ntohll (amsg->request_id);
1219 servicename = (const char *) &amsg[1];
1221 if (GNUNET_YES == in_shutdown)
1222 {
1223 signal_result (client,
1224 servicename,
1225 request_id,
1227 return;
1228 }
1229 sl = find_service (servicename);
1230 if (NULL == sl)
1231 {
1232 signal_result (client,
1233 servicename,
1234 request_id,
1236 return;
1237 }
1238 sl->force_start = GNUNET_YES;
1239 if (NULL != sl->proc)
1240 {
1241 signal_result (client,
1242 servicename,
1243 request_id,
1245 return;
1246 }
1247 start_process (sl, client, request_id);
1248}

References find_service(), ServiceList::force_start, GNUNET_ARM_RESULT_IN_SHUTDOWN, GNUNET_ARM_RESULT_IS_NOT_KNOWN, GNUNET_ARM_RESULT_IS_STARTED_ALREADY, GNUNET_ntohll(), GNUNET_SERVICE_client_continue(), GNUNET_YES, in_shutdown, ServiceList::proc, GNUNET_ARM_Message::request_id, signal_result(), and start_process().

Here is the call graph for this function:

◆ trigger_shutdown()

static void trigger_shutdown ( void *  cls)
static

Start a shutdown sequence.

Parameters
clsclosure (refers to service)

Definition at line 1257 of file gnunet-service-arm.c.

1258{
1259 (void) cls;
1260 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Triggering shutdown\n");
1262}

References GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, and GNUNET_SCHEDULER_shutdown().

Referenced by handle_stop().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_stop()

static int check_stop ( void *  cls,
const struct GNUNET_ARM_Message amsg 
)
static

Check STOP-message.

Parameters
clsidentification of the client
amsgthe actual message
Returns
GNUNET_OK to keep the connection open, GNUNET_SYSERR to close it (signal serious error)

Definition at line 1274 of file gnunet-service-arm.c.

1275{
1276 (void) cls;
1278 return GNUNET_OK;
1279}

References GNUNET_MQ_check_zero_termination, and GNUNET_OK.

◆ handle_stop()

static void handle_stop ( void *  cls,
const struct GNUNET_ARM_Message amsg 
)
static

Handle STOP-message.

Parameters
clsidentification of the client
amsgthe actual message

Definition at line 1289 of file gnunet-service-arm.c.

1290{
1291 struct GNUNET_SERVICE_Client *client = cls;
1292 struct ServiceList *sl;
1293 const char *servicename;
1294 uint64_t request_id;
1295
1296 request_id = GNUNET_ntohll (amsg->request_id);
1297 servicename = (const char *) &amsg[1];
1299 _ ("Preparing to stop `%s'\n"),
1300 servicename);
1302 if (0 == strcasecmp (servicename, "arm"))
1303 {
1304 broadcast_status (servicename, GNUNET_ARM_SERVICE_STOPPING, NULL);
1305 signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_STOPPING);
1308 return;
1309 }
1310 sl = find_service (servicename);
1311 if (NULL == sl)
1312 {
1313 signal_result (client,
1314 servicename,
1315 request_id,
1317 return;
1318 }
1319 sl->force_start = GNUNET_NO;
1320 if (GNUNET_YES == in_shutdown)
1321 {
1322 /* shutdown in progress */
1323 signal_result (client,
1324 servicename,
1325 request_id,
1327 return;
1328 }
1329 if (NULL != sl->killing_client)
1330 {
1331 /* killing already in progress */
1332 signal_result (client,
1333 servicename,
1334 request_id,
1336 return;
1337 }
1338 if (NULL == sl->proc)
1339 {
1340 /* process is down */
1341 signal_result (client,
1342 servicename,
1343 request_id,
1345 return;
1346 }
1348 "Sending kill signal to service `%s', waiting for process to die.\n",
1349 servicename);
1350 broadcast_status (servicename, GNUNET_ARM_SERVICE_STOPPING, NULL);
1351 /* no signal_start - only when it's STOPPED */
1355 sl->killing_client = client;
1356 sl->killing_client_request_id = request_id;
1357}

References _, broadcast_status(), find_service(), ServiceList::force_start, GNUNET_ARM_RESULT_IN_SHUTDOWN, GNUNET_ARM_RESULT_IS_NOT_KNOWN, GNUNET_ARM_RESULT_IS_STOPPED_ALREADY, GNUNET_ARM_RESULT_IS_STOPPING_ALREADY, GNUNET_ARM_RESULT_STOPPING, GNUNET_ARM_SERVICE_STOPPING, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_ERROR_TYPE_WARNING, GNUNET_log, GNUNET_log_strerror, GNUNET_NO, GNUNET_ntohll(), GNUNET_OS_process_kill(), GNUNET_SCHEDULER_add_now(), GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_persist(), GNUNET_TERM_SIG, GNUNET_TIME_absolute_get(), GNUNET_YES, in_shutdown, ServiceList::killed_at, ServiceList::killing_client, ServiceList::killing_client_request_id, ServiceList::proc, GNUNET_ARM_Message::request_id, signal_result(), and trigger_shutdown().

Here is the call graph for this function:

◆ pool_write()

static int pool_write ( char *  pool_start,
size_t  pool_size,
size_t *  pool_pos,
char *  str 
)
static

Write a string to a string pool.

Parameters
pool_startpointer to the start of the string pool
pool_sizesize of the string pool
[in,out]pool_poscurrent position index in the string pool, will be updated
strstring to write to the string pool
Returns
GNUNET_OK if the string fits into the pool, GNUNET_SYSERR otherwise

Definition at line 1372 of file gnunet-service-arm.c.

1373{
1374 size_t next_pos = (*pool_pos) + strlen (str) + 1;
1375
1376 if (next_pos > pool_size)
1377 return GNUNET_SYSERR;
1378 memcpy (pool_start + *pool_pos, str, strlen (str) + 1);
1379 *pool_pos = next_pos;
1380 return GNUNET_OK;
1381}

References GNUNET_OK, and GNUNET_SYSERR.

Referenced by handle_list().

Here is the caller graph for this function:

◆ handle_list()

static void handle_list ( void *  cls,
const struct GNUNET_ARM_Message request 
)
static

Handle LIST-message.

Parameters
clsidentification of the client
requestthe actual message

Definition at line 1391 of file gnunet-service-arm.c.

1392{
1393 struct GNUNET_SERVICE_Client *client = cls;
1394 struct GNUNET_MQ_Envelope *env;
1396 size_t extra_size;
1397 struct ServiceList *sl;
1398 uint16_t count;
1399 size_t pool_size;
1400 size_t pool_pos;
1401 char *pool_start;
1403
1404 GNUNET_break_op (0 == ntohl (request->reserved));
1405 count = 0;
1406 pool_size = 0;
1407
1408 /* Do one pass over the list to compute the number of services
1409 * and the string pool size */
1410 for (sl = running_head; NULL != sl; sl = sl->next)
1411 {
1412 pool_size += strlen (sl->name) + 1;
1413 pool_size += strlen (sl->binary) + 1;
1414 count++;
1415 }
1416
1417 extra_size = pool_size + (count * sizeof (struct
1420 extra_size,
1422 msg->arm_msg.request_id = request->request_id;
1423 msg->count = htons (count);
1424
1425 ssm = (struct GNUNET_ARM_ServiceInfoMessage *) &msg[1];
1426 pool_start = (char *) (ssm + count);
1427 pool_pos = 0;
1428
1429 for (sl = running_head; NULL != sl; sl = sl->next)
1430 {
1431 ssm->name_index = htons ((uint16_t) pool_pos);
1432 GNUNET_assert (GNUNET_OK == pool_write (pool_start, pool_size, &pool_pos,
1433 sl->name));
1434 ssm->binary_index = htons ((uint16_t) pool_pos);
1435 GNUNET_assert (GNUNET_OK == pool_write (pool_start, pool_size, &pool_pos,
1436 sl->binary));
1437 if (NULL == sl->proc)
1438 {
1439 if (0 == sl->last_started_at.abs_value_us)
1440 {
1441 /* Process never started */
1443 }
1444 else if (0 == sl->last_exit_status)
1445 {
1447 }
1448 else
1449 {
1451 ssm->last_exit_status = htons (sl->last_exit_status);
1452 }
1453 }
1454 else if ((NULL != sl->killing_client) || (GNUNET_YES == in_shutdown))
1455 {
1457 }
1458 else
1459 {
1461 }
1464 ssm++;
1465 }
1468}

References GNUNET_TIME_Absolute::abs_value_us, ServiceList::binary, GNUNET_ARM_ServiceInfoMessage::binary_index, env, GNUNET_ARM_SERVICE_STATUS_FAILED, GNUNET_ARM_SERVICE_STATUS_FINISHED, GNUNET_ARM_SERVICE_STATUS_STARTED, GNUNET_ARM_SERVICE_STATUS_STOPPED, GNUNET_ARM_SERVICE_STATUS_STOPPING, GNUNET_assert, GNUNET_break_op, GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT, GNUNET_MQ_msg_extra, GNUNET_MQ_send(), GNUNET_OK, GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_get_mq(), GNUNET_TIME_absolute_hton(), GNUNET_YES, in_shutdown, ServiceList::killing_client, GNUNET_ARM_ServiceInfoMessage::last_exit_status, ServiceList::last_exit_status, GNUNET_ARM_ServiceInfoMessage::last_started_at, ServiceList::last_started_at, msg, ServiceList::name, GNUNET_ARM_ServiceInfoMessage::name_index, ServiceList::next, pool_write(), ServiceList::proc, request, GNUNET_VPN_RedirectionRequest::request_id, GNUNET_ARM_ServiceInfoMessage::restart_at, ServiceList::restart_at, running_head, and GNUNET_ARM_ServiceInfoMessage::status.

Here is the call graph for this function:

◆ handle_test()

static void handle_test ( void *  cls,
const struct GNUNET_MessageHeader message 
)
static

Handle TEST-message by sending back TEST.

Parameters
clsidentification of the client
messagethe actual message

Definition at line 1478 of file gnunet-service-arm.c.

1479{
1480 struct GNUNET_SERVICE_Client *client = cls;
1481 struct GNUNET_MQ_Envelope *env;
1482 struct GNUNET_MessageHeader *msg;
1483
1484 (void) message;
1488}

References env, GNUNET_MESSAGE_TYPE_ARM_TEST, GNUNET_MQ_msg, GNUNET_MQ_send(), GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_get_mq(), and msg.

Here is the call graph for this function:

◆ do_shutdown()

static void do_shutdown ( )
static

We are done with everything.

Stop remaining tasks, signal handler and the server.

Definition at line 1496 of file gnunet-service-arm.c.

1497{
1498 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Last shutdown phase\n");
1499 if (NULL != notifier)
1500 {
1502 notifier = NULL;
1503 }
1504 if (NULL != service)
1505 {
1507 service = NULL;
1508 }
1509 if (NULL != child_death_task)
1510 {
1512 child_death_task = NULL;
1513 }
1514}

References child_death_task, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_notification_context_destroy(), GNUNET_SCHEDULER_cancel(), GNUNET_SERVICE_shutdown(), notifier, and service.

Referenced by maint_child_death(), and shutdown_task().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ list_count()

static unsigned int list_count ( struct ServiceList run_head)
static

Count how many services are still active.

Parameters
running_headlist of services
Returns
number of active services found

Definition at line 1524 of file gnunet-service-arm.c.

1525{
1526 struct ServiceList *i;
1527 unsigned int res;
1528
1529 for (res = 0, i = run_head; NULL != i; i = i->next, res++)
1531 return res;
1532}

References GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, ServiceList::name, ServiceList::next, and res.

Referenced by maint_child_death(), and shutdown_task().

Here is the caller graph for this function:

◆ shutdown_task()

static void shutdown_task ( void *  cls)
static

Task run for shutdown.

Parameters
clsclosure, NULL if we need to self-restart

Definition at line 1541 of file gnunet-service-arm.c.

1542{
1543 struct ServiceList *pos;
1544 struct ServiceList *nxt;
1545 struct ServiceListeningInfo *sli;
1546
1547 (void) cls;
1548 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "First shutdown phase\n");
1549 if (NULL != child_restart_task)
1550 {
1552 child_restart_task = NULL;
1553 }
1555 /* first, stop listening */
1556 for (pos = running_head; NULL != pos; pos = pos->next)
1557 {
1558 while (NULL != (sli = pos->listen_head))
1559 {
1561 if (NULL != sli->accept_task)
1562 {
1564 sli->accept_task = NULL;
1565 }
1569 GNUNET_free (sli);
1570 }
1571 }
1572 /* then, shutdown all existing service processes */
1573 nxt = running_head;
1574 while (NULL != (pos = nxt))
1575 {
1576 nxt = pos->next;
1577 if (NULL != pos->proc)
1578 {
1579 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping service `%s'\n", pos->name);
1583 }
1584 else
1585 {
1586 free_service (pos);
1587 }
1588 }
1589 /* finally, should all service processes be already gone, terminate for real */
1590 if (NULL == running_head)
1591 do_shutdown ();
1592 else
1594 "Delaying shutdown, have %u children still running\n",
1596}

References ServiceListeningInfo::accept_task, child_restart_task, do_shutdown(), free_service(), GNUNET_break, GNUNET_CONTAINER_DLL_remove, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_log, GNUNET_log_strerror, GNUNET_NETWORK_socket_close(), GNUNET_OK, GNUNET_OS_process_kill(), GNUNET_SCHEDULER_cancel(), GNUNET_TERM_SIG, GNUNET_TIME_absolute_get(), GNUNET_YES, in_shutdown, ServiceList::killed_at, list_count(), ServiceList::listen_head, ServiceListeningInfo::listen_socket, ServiceList::listen_tail, ServiceList::name, ServiceList::next, ServiceList::proc, running_head, and ServiceListeningInfo::service_addr.

Here is the call graph for this function:

◆ delayed_restart_task()

static void delayed_restart_task ( void *  cls)
static

Task run whenever it is time to restart a child that died.

Parameters
clsclosure, always NULL

Definition at line 1605 of file gnunet-service-arm.c.

1607{
1608 struct ServiceList *sl;
1609 struct GNUNET_TIME_Relative lowestRestartDelay;
1610 struct ServiceListeningInfo *sli;
1611
1612 (void) cls;
1613 child_restart_task = NULL;
1615 lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL;
1616
1617 /* check for services that need to be restarted due to
1618 * configuration changes or because the last restart failed */
1619 for (sl = running_head; NULL != sl; sl = sl->next)
1620 {
1621 if (NULL != sl->proc)
1622 continue;
1623 /* service is currently not running */
1625 {
1626 /* restart is now allowed */
1627 if (sl->force_start)
1628 {
1629 /* process should run by default, start immediately */
1631 _ ("Restarting service `%s'.\n"),
1632 sl->name);
1633 start_process (sl, NULL, 0);
1634 }
1635 else
1636 {
1637 /* process is run on-demand, ensure it is re-started if there is demand */
1638 for (sli = sl->listen_head; NULL != sli; sli = sli->next)
1639 if (NULL == sli->accept_task)
1640 {
1641 /* accept was actually paused, so start it again */
1642 sli->accept_task =
1644 sli->listen_socket,
1646 sli);
1647 }
1648 }
1649 }
1650 else
1651 {
1652 /* update calculation for earliest time to reactivate a service */
1653 lowestRestartDelay =
1654 GNUNET_TIME_relative_min (lowestRestartDelay,
1656 sl->restart_at));
1657 }
1658 }
1659 if (lowestRestartDelay.rel_value_us !=
1660 GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1661 {
1663 "Will restart process in %s\n",
1664 GNUNET_STRINGS_relative_time_to_string (lowestRestartDelay,
1665 GNUNET_YES));
1670 NULL);
1671 }
1672}

References _, accept_connection(), ServiceListeningInfo::accept_task, child_restart_task, delayed_restart_task(), ServiceList::force_start, GNUNET_assert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_log, GNUNET_NO, GNUNET_SCHEDULER_add_delayed_with_priority(), GNUNET_SCHEDULER_add_read_net(), GNUNET_SCHEDULER_PRIORITY_IDLE, GNUNET_STRINGS_relative_time_to_string(), GNUNET_TIME_absolute_get_remaining(), GNUNET_TIME_relative_min(), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, in_shutdown, ServiceList::listen_head, ServiceListeningInfo::listen_socket, ServiceList::name, ServiceListeningInfo::next, ServiceList::next, ServiceList::proc, GNUNET_TIME_Relative::rel_value_us, ServiceList::restart_at, running_head, ServiceListeningInfo::sl, and start_process().

Referenced by delayed_restart_task(), and maint_child_death().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ maint_child_death()

static void maint_child_death ( void *  cls)
static

Task triggered whenever we receive a SIGCHLD (child process died).

Parameters
clsclosure, NULL

Definition at line 1682 of file gnunet-service-arm.c.

1683{
1684 struct ServiceList *pos;
1685 struct ServiceList *next;
1686 struct ServiceListeningInfo *sli;
1687 const char *statstr;
1688 int statcode;
1689 int ret;
1690 char c[16];
1691 enum GNUNET_OS_ProcessStatusType statusType;
1692 unsigned long statusCode;
1693 const struct GNUNET_DISK_FileHandle *pr;
1694
1695 (void) cls;
1697 child_death_task = NULL;
1698 /* consume the signal */
1699 GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof(c)));
1700
1701 /* check for services that died (WAITPID) */
1702 next = running_head;
1703 while (NULL != (pos = next))
1704 {
1705 next = pos->next;
1706
1707 if (NULL == pos->proc)
1708 {
1709 if (GNUNET_YES == in_shutdown)
1710 free_service (pos);
1711 continue;
1712 }
1713#if HAVE_WAIT4
1714 if (NULL != wait_file)
1715 {
1716 /* need to use 'wait4()' to obtain and log performance data */
1717 struct rusage ru;
1718 int status;
1719 pid_t pid;
1720
1722 ret = wait4 (pid, &status, WNOHANG, &ru);
1723 if (ret <= 0)
1724 continue; /* no process done */
1725 if (WIFEXITED (status))
1726 {
1727 statusType = GNUNET_OS_PROCESS_EXITED;
1728 statusCode = WEXITSTATUS (status);
1729 }
1730 else if (WIFSIGNALED (status))
1731 {
1732 statusType = GNUNET_OS_PROCESS_SIGNALED;
1733 statusCode = WTERMSIG (status);
1734 }
1735 else if (WIFSTOPPED (status))
1736 {
1737 statusType = GNUNET_OS_PROCESS_SIGNALED;
1738 statusCode = WSTOPSIG (status);
1739 }
1740#ifdef WIFCONTINUED
1741 else if (WIFCONTINUED (status))
1742 {
1743 statusType = GNUNET_OS_PROCESS_RUNNING;
1744 statusCode = 0;
1745 }
1746#endif
1747 else
1748 {
1749 statusType = GNUNET_OS_PROCESS_UNKNOWN;
1750 statusCode = 0;
1751 }
1752 if ((GNUNET_OS_PROCESS_EXITED == statusType) ||
1753 (GNUNET_OS_PROCESS_SIGNALED == statusType))
1754 {
1755 double utime = ru.ru_utime.tv_sec + (ru.ru_utime.tv_usec / 10e6);
1756 double stime = ru.ru_stime.tv_sec + (ru.ru_stime.tv_usec / 10e6);
1757 fprintf (wait_file,
1758 "%s(%u) %.3f %.3f %llu %llu %llu %llu %llu\n",
1759 pos->binary,
1760 (unsigned int) pid,
1761 utime,
1762 stime,
1763 (unsigned long long) ru.ru_maxrss,
1764 (unsigned long long) ru.ru_inblock,
1765 (unsigned long long) ru.ru_oublock,
1766 (unsigned long long) ru.ru_nvcsw,
1767 (unsigned long long) ru.ru_nivcsw);
1768 }
1769 }
1770 else /* continue with JUST this "if" as "else" (intentionally no brackets!) */
1771#endif
1773 &statusType,
1774 &statusCode))) ||
1775 (ret == GNUNET_NO) || (statusType == GNUNET_OS_PROCESS_STOPPED) ||
1776 (statusType == GNUNET_OS_PROCESS_UNKNOWN) ||
1777 (statusType == GNUNET_OS_PROCESS_RUNNING))
1778 continue;
1779
1780 if (statusType == GNUNET_OS_PROCESS_EXITED)
1781 {
1782 statstr = _ (/* process termination method */ "exit");
1783 statcode = statusCode;
1784 }
1785 else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
1786 {
1787 statstr = _ (/* process termination method */ "signal");
1788 statcode = statusCode;
1789 }
1790 else
1791 {
1792 statstr = _ (/* process termination method */ "unknown");
1793 statcode = 0;
1794 }
1795 if (0 != pos->killed_at.abs_value_us)
1796 {
1798 _ ("Service `%s' took %s to terminate\n"),
1799 pos->name,
1802 GNUNET_YES));
1803 }
1805 pos->proc = NULL;
1807 if (NULL != pos->killing_client)
1808 {
1810 pos->name,
1813 pos->killing_client = NULL;
1815 }
1816 if (GNUNET_YES != in_shutdown)
1817 {
1818 pos->last_exit_status = statcode;
1819 if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0))
1820 {
1821 /* process terminated normally, allow restart at any time */
1822 pos->restart_at.abs_value_us = 0;
1823 GNUNET_log (
1825 _ ("Service `%s' terminated normally, will restart at any time\n"),
1826 pos->name);
1827 /* process can still be re-started on-demand, ensure it is re-started if there is demand */
1828 for (sli = pos->listen_head; NULL != sli; sli = sli->next)
1829 {
1830 GNUNET_break (NULL == sli->accept_task);
1831 sli->accept_task =
1833 sli->listen_socket,
1835 sli);
1836 }
1837 }
1838 else
1839 {
1840 GNUNET_log (
1842 _ ("Service `%s' terminated with status %s/%d, will restart in %s\n"),
1843 pos->name,
1844 statstr,
1845 statcode,
1847 {
1848 /* Reduce backoff based on runtime of the process,
1849 so that there is a cool-down if a process actually
1850 runs for a while. */
1851 struct GNUNET_TIME_Relative runtime;
1852 unsigned int minutes;
1853
1855 minutes =
1856 runtime.rel_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us;
1857 if (minutes > 31)
1859 else
1860 pos->backoff.rel_value_us >>= minutes;
1861 }
1862 /* schedule restart */
1865 if (NULL != child_restart_task)
1870 NULL);
1871 }
1872 }
1873 else
1874 {
1875 free_service (pos);
1876 }
1877 }
1880 pr,
1882 NULL);
1883 if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
1884 do_shutdown ();
1885 else if (GNUNET_YES == in_shutdown)
1887 "Delaying shutdown after child's death, still have %u children\n",
1889}

References _, GNUNET_TIME_Absolute::abs_value_us, accept_connection(), ServiceListeningInfo::accept_task, ServiceList::backoff, ServiceList::binary, broadcast_status(), child_death_task, child_restart_task, delayed_restart_task(), do_shutdown(), free_service(), GNUNET_ARM_RESULT_STOPPED, GNUNET_ARM_SERVICE_STOPPED, GNUNET_break, GNUNET_DISK_file_read(), GNUNET_DISK_PIPE_END_READ, GNUNET_DISK_pipe_handle(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_ERROR_TYPE_WARNING, GNUNET_log, GNUNET_NO, GNUNET_OS_process_destroy(), GNUNET_OS_PROCESS_EXITED, GNUNET_OS_process_get_pid(), GNUNET_OS_PROCESS_RUNNING, GNUNET_OS_PROCESS_SIGNALED, GNUNET_OS_process_status(), GNUNET_OS_PROCESS_STOPPED, GNUNET_OS_PROCESS_UNKNOWN, GNUNET_SCHEDULER_add_read_file(), GNUNET_SCHEDULER_add_read_net(), GNUNET_SCHEDULER_add_with_priority(), GNUNET_SCHEDULER_cancel(), GNUNET_SCHEDULER_PRIORITY_IDLE, GNUNET_STRINGS_relative_time_to_string(), GNUNET_SYSERR, GNUNET_TIME_absolute_get_duration(), GNUNET_TIME_relative_to_absolute(), GNUNET_TIME_STD_BACKOFF, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_TIME_UNIT_MINUTES, GNUNET_TIME_UNIT_ZERO, GNUNET_YES, in_shutdown, ServiceList::killed_at, ServiceList::killing_client, ServiceList::killing_client_request_id, ServiceList::last_exit_status, list_count(), ServiceList::listen_head, ServiceListeningInfo::listen_socket, maint_child_death(), ServiceList::name, ServiceListeningInfo::next, ServiceList::next, pid, ServiceList::proc, GNUNET_TIME_Relative::rel_value_us, ServiceList::restart_at, ret, running_head, signal_result(), sigpipe, and status.

Referenced by maint_child_death(), and run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sighandler_child_death()

static void sighandler_child_death ( void  )
static

Signal handler called for SIGCHLD.

Triggers the respective handler by writing to the trigger pipe.

Definition at line 1897 of file gnunet-service-arm.c.

1898{
1899 static char c;
1900 int old_errno = errno; /* back-up errno */
1901
1902 GNUNET_break (
1903 1 ==
1906 ,
1907 &c,
1908 sizeof(c)));
1909 errno = old_errno; /* restore errno */
1910}

References GNUNET_break, GNUNET_DISK_file_write(), GNUNET_DISK_PIPE_END_WRITE, GNUNET_DISK_pipe_handle(), and sigpipe.

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setup_service()

static void setup_service ( void *  cls,
const char *  section 
)
static

Setup our service record for the given section in the configuration file (assuming the section is for a service).

Parameters
clsunused
sectiona section in the configuration file
Returns
GNUNET_OK (continue)

Definition at line 1922 of file gnunet-service-arm.c.

1923{
1924 struct ServiceList *sl;
1925 char *binary;
1926 char *config;
1927 struct stat sbuf;
1928 struct sockaddr **addrs;
1929 socklen_t *addr_lens;
1930 int ret;
1931
1932 (void) cls;
1933 if (0 == strcasecmp (section, "arm"))
1934 return;
1935 if (GNUNET_OK !=
1936 GNUNET_CONFIGURATION_get_value_string (cfg, section, "BINARY", &binary))
1937 {
1938 /* not a service section */
1939 return;
1940 }
1941 if (GNUNET_YES ==
1943 section,
1944 "RUN_PER_USER"))
1945 {
1946 if (GNUNET_NO == start_user)
1947 {
1948 GNUNET_free (binary);
1949 return; /* user service, and we don't deal with those */
1950 }
1951 }
1952 else
1953 {
1954 if (GNUNET_NO == start_system)
1955 {
1956 GNUNET_free (binary);
1957 return; /* system service, and we don't deal with those */
1958 }
1959 }
1960 sl = find_service (section);
1961 if (NULL != sl)
1962 {
1963 /* got the same section twice!? */
1964 GNUNET_break (0);
1965 GNUNET_free (binary);
1966 return;
1967 }
1968 config = NULL;
1969 if (((GNUNET_OK !=
1971 section,
1972 "CONFIG",
1973 &config)) &&
1974 (GNUNET_OK !=
1976 "PATHS",
1977 "DEFAULTCONFIG",
1978 &config))) ||
1979 (0 != stat (config,
1980 &sbuf)))
1981 {
1982 if (NULL != config)
1983 {
1985 section,
1986 "CONFIG",
1987 strerror (errno));
1989 config = NULL;
1990 }
1991 }
1992 sl = GNUNET_new (struct ServiceList);
1993 sl->name = GNUNET_strdup (section);
1994 sl->binary = binary;
1995 sl->config = config;
1998 sl->pipe_control =
1999 (GNUNET_YES ==
2001 section,
2002 "PIPECONTROL"));
2005 sl);
2006 if (GNUNET_YES ==
2008 section,
2009 "IMMEDIATE_START"))
2010 {
2011 sl->force_start = GNUNET_YES;
2012 if (GNUNET_YES ==
2014 section,
2015 "NOARMBIND"))
2016 return;
2017 }
2018 else
2019 {
2020 if (GNUNET_YES !=
2022 section,
2023 "START_ON_DEMAND"))
2024 return;
2025 }
2026 if (0 >= (ret = get_server_addresses (section,
2027 cfg,
2028 &addrs,
2029 &addr_lens)))
2030 return;
2031 /* this will free (or capture) addrs[i] */
2032 for (unsigned int i = 0; i < (unsigned int) ret; i++)
2033 create_listen_socket (addrs[i], addr_lens[i], sl);
2034 GNUNET_free (addrs);
2035 GNUNET_free (addr_lens);
2036}

References ServiceList::backoff, ServiceList::binary, cfg, config, ServiceList::config, create_listen_socket(), find_service(), ServiceList::force_start, get_server_addresses(), GNUNET_break, GNUNET_CONFIGURATION_get_value_filename(), GNUNET_CONFIGURATION_get_value_string(), GNUNET_CONFIGURATION_get_value_yesno(), GNUNET_CONTAINER_DLL_insert, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_log_config_invalid(), GNUNET_new, GNUNET_NO, GNUNET_OK, GNUNET_strdup, GNUNET_TIME_UNIT_FOREVER_ABS, GNUNET_TIME_UNIT_MILLISECONDS, GNUNET_YES, ServiceList::name, ServiceList::pipe_control, ServiceList::restart_at, ret, running_head, running_tail, start_system, and start_user.

Referenced by run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ client_connect_cb()

static void * client_connect_cb ( void *  cls,
struct GNUNET_SERVICE_Client client,
struct GNUNET_MQ_Handle mq 
)
static

A client connected, mark as a monitoring client.

Parameters
clsclosure
clientidentification of the client
mqqueue to talk to client
Returns
client

Definition at line 2048 of file gnunet-service-arm.c.

2051{
2052 /* All clients are considered to be of the "monitor" kind
2053 * (that is, they don't affect ARM shutdown).
2054 */
2055 (void) cls;
2056 (void) mq;
2058 return client;
2059}

References GNUNET_SERVICE_client_mark_monitor(), and mq.

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ client_disconnect_cb()

static void client_disconnect_cb ( void *  cls,
struct GNUNET_SERVICE_Client client,
void *  app_ctx 
)
static

A client disconnected, clean up associated state.

Parameters
clsclosure
clientidentification of the client
app_ctxmust match client

Definition at line 2070 of file gnunet-service-arm.c.

2073{
2074 (void) cls;
2075 GNUNET_assert (client == app_ctx);
2076 for (struct ServiceList *sl = running_head; NULL != sl; sl = sl->next)
2077 if (sl->killing_client == client)
2078 sl->killing_client = NULL;
2079}

References GNUNET_assert, ServiceList::next, and running_head.

Referenced by main().

Here is the caller graph for this function:

◆ handle_monitor()

static void handle_monitor ( void *  cls,
const struct GNUNET_MessageHeader message 
)
static

Handle MONITOR-message.

Parameters
clsidentification of the client
messagethe actual message
Returns
GNUNET_OK to keep the connection open, GNUNET_SYSERR to close it (signal serious error)

Definition at line 2091 of file gnunet-service-arm.c.

2092{
2093 struct GNUNET_SERVICE_Client *client = cls;
2094
2095 (void) message;
2096 /* FIXME: might want to start by letting monitor know about
2097 services that are already running */
2098 /* Removal is handled by the server implementation, internally. */
2103}

References broadcast_status(), GNUNET_ARM_SERVICE_MONITORING_STARTED, GNUNET_notification_context_add(), GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_get_mq(), and notifier.

Here is the call graph for this function:

◆ run()

static void run ( void *  cls,
const struct GNUNET_CONFIGURATION_Handle c,
struct GNUNET_SERVICE_Handle serv 
)
static

Process arm requests.

Parameters
clsclosure, NULL
servthe initialized service
cconfiguration to use

Definition at line 2114 of file gnunet-service-arm.c.

2117{
2118 struct ServiceList *sl;
2119 enum GNUNET_GenericReturnValue ret1;
2120 enum GNUNET_GenericReturnValue ret2;
2121
2122 (void) cls;
2123 cfg = c;
2124 service = serv;
2131 NULL);
2132#if HAVE_WAIT4
2133 if (GNUNET_OK ==
2135 "ARM",
2136 "RESOURCE_DIAGNOSTICS",
2137 &wait_filename))
2138 {
2139 wait_file = fopen (wait_filename, "w");
2140 if (NULL == wait_file)
2141 {
2143 "fopen",
2144 wait_filename);
2145 }
2146 }
2147#endif
2148 if (GNUNET_OK !=
2150 "ARM",
2151 "GLOBAL_PREFIX",
2154 else
2156 if (GNUNET_OK !=
2158 "ARM",
2159 "GLOBAL_POSTFIX",
2160 &final_option))
2162 else
2165 "ARM",
2166 "START_SYSTEM_SERVICES");
2168 "ARM",
2169 "START_USER_SERVICES");
2170 if ( (GNUNET_SYSERR == ret1) ||
2171 (GNUNET_SYSERR == ret2) )
2172 {
2173 /* invalid option */
2174 GNUNET_break (0);
2176 global_ret = 1;
2177 return;
2178 }
2180 "ARM",
2181 "START_SYSTEM_SERVICES"))
2182 ret1 = GNUNET_SYSERR;
2184 "ARM",
2185 "START_USER_SERVICES"))
2186 ret2 = GNUNET_SYSERR;
2187 start_system = (GNUNET_YES == ret1) ||
2188 ( (GNUNET_SYSERR == ret1) && (GNUNET_SYSERR == ret2) );
2189 start_user = (GNUNET_YES == ret2) ||
2190 ( (GNUNET_SYSERR == ret1) && (GNUNET_SYSERR == ret2) );
2191 if ( (GNUNET_NO == start_user) &&
2192 (GNUNET_NO == start_system) )
2193 {
2194 GNUNET_log (
2196 "Please enable either START_USER_SERVICES or START_SYSTEM_SERVICES\n");
2198 global_ret = 1;
2199 return;
2200 }
2203 NULL);
2204
2205 /* start default services... */
2206 for (sl = running_head; NULL != sl; sl = sl->next)
2207 if (GNUNET_YES == sl->force_start)
2208 start_process (sl, NULL, 0);
2210}

References cfg, child_death_task, final_option, ServiceList::force_start, global_ret, GNUNET_break, GNUNET_CONFIGURATION_expand_dollar(), GNUNET_CONFIGURATION_get_value_filename(), GNUNET_CONFIGURATION_get_value_string(), GNUNET_CONFIGURATION_get_value_yesno(), GNUNET_CONFIGURATION_have_value(), GNUNET_CONFIGURATION_iterate_sections(), GNUNET_DISK_PIPE_END_READ, GNUNET_DISK_pipe_handle(), GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_log_strerror_file, GNUNET_NO, GNUNET_notification_context_create(), GNUNET_OK, GNUNET_SCHEDULER_add_read_file(), GNUNET_SCHEDULER_add_shutdown(), GNUNET_SCHEDULER_shutdown(), GNUNET_strdup, GNUNET_SYSERR, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, maint_child_death(), MAX_NOTIFY_QUEUE, ServiceList::next, notifier, prefix_command, running_head, service, setup_service(), shutdown_task, sigpipe, start_process(), start_system, and start_user.

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ main()

int main ( int  argc,
char *const *  argv 
)

The main function for the arm service.

Parameters
argcnumber of arguments from the command line
argvcommand line arguments
Returns
0 ok, 1 on error

Definition at line 2221 of file gnunet-service-arm.c.

2222{
2227 struct GNUNET_ARM_Message,
2228 NULL),
2231 struct GNUNET_ARM_Message,
2232 NULL),
2235 struct GNUNET_MessageHeader,
2236 NULL),
2239 struct GNUNET_ARM_Message,
2240 NULL),
2243 struct GNUNET_MessageHeader,
2244 NULL),
2246 };
2247
2249 GNUNET_assert (NULL != sigpipe);
2250 shc_chld =
2254 argc,
2255 argv,
2256 "arm",
2259 &run,
2262 NULL,
2263 handlers))
2264 global_ret = 2;
2265#if HAVE_WAIT4
2266 if (NULL != wait_file)
2267 {
2268 fclose (wait_file);
2269 wait_file = NULL;
2270 }
2271 if (NULL != wait_filename)
2272 {
2273 GNUNET_free (wait_filename);
2274 wait_filename = NULL;
2275 }
2276#endif
2278 shc_chld = NULL;
2280 sigpipe = NULL;
2281 return global_ret;
2282}

References client_connect_cb(), client_disconnect_cb(), global_ret, GNUNET_assert, GNUNET_DISK_PF_NONE, GNUNET_DISK_pipe(), GNUNET_DISK_pipe_close(), GNUNET_free, GNUNET_MESSAGE_TYPE_ARM_LIST, GNUNET_MESSAGE_TYPE_ARM_MONITOR, GNUNET_MESSAGE_TYPE_ARM_START, GNUNET_MESSAGE_TYPE_ARM_STOP, GNUNET_MESSAGE_TYPE_ARM_TEST, GNUNET_MQ_handler_end, GNUNET_MQ_hd_fixed_size, GNUNET_MQ_hd_var_size, GNUNET_OS_project_data_gnunet(), GNUNET_SERVICE_OPTION_CLOSE_LSOCKS, GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN, GNUNET_SERVICE_run_(), GNUNET_SIGCHLD, GNUNET_SIGNAL_handler_install(), GNUNET_SIGNAL_handler_uninstall(), handlers, list, monitor, run(), shc_chld, sighandler_child_death(), sigpipe, and start.

Here is the call graph for this function:

Variable Documentation

◆ running_head

struct ServiceList* running_head
static

◆ running_tail

struct ServiceList* running_tail
static

List of running services.

Definition at line 211 of file gnunet-service-arm.c.

Referenced by free_service(), and setup_service().

◆ cfg

const struct GNUNET_CONFIGURATION_Handle* cfg
static

Our configuration.

Definition at line 216 of file gnunet-service-arm.c.

Referenced by create_listen_socket(), get_server_addresses(), run(), setup_service(), and start_process().

◆ prefix_command

char* prefix_command
static

Command to prepend to each actual command.

Definition at line 221 of file gnunet-service-arm.c.

Referenced by run(), and start_process().

◆ final_option

char* final_option
static

Option to append to each actual command.

Definition at line 226 of file gnunet-service-arm.c.

Referenced by run(), and start_process().

◆ child_death_task

struct GNUNET_SCHEDULER_Task* child_death_task
static

ID of task called whenever we get a SIGCHILD.

Definition at line 231 of file gnunet-service-arm.c.

Referenced by do_shutdown(), maint_child_death(), and run().

◆ child_restart_task

struct GNUNET_SCHEDULER_Task* child_restart_task
static

ID of task called whenever the timeout for restarting a child expires.

Definition at line 237 of file gnunet-service-arm.c.

Referenced by delayed_restart_task(), maint_child_death(), and shutdown_task().

◆ sigpipe

struct GNUNET_DISK_PipeHandle* sigpipe
static

Pipe used to communicate shutdown via signal.

Definition at line 242 of file gnunet-service-arm.c.

Referenced by main(), maint_child_death(), run(), and sighandler_child_death().

◆ in_shutdown

int in_shutdown
static

◆ global_ret

int global_ret
static

Return value from main.

Definition at line 252 of file gnunet-service-arm.c.

Referenced by main(), and run().

◆ start_user

int start_user = GNUNET_YES
static

Are we starting user services?

Definition at line 257 of file gnunet-service-arm.c.

Referenced by run(), and setup_service().

◆ start_system

int start_system = GNUNET_YES
static

Are we starting system services?

Definition at line 262 of file gnunet-service-arm.c.

Referenced by run(), and setup_service().

◆ service

struct GNUNET_SERVICE_Handle* service
static

Handle to our service instance.

Our service is a bit special in that its service is not immediately stopped once we get a shutdown request (since we need to continue service until all of our child processes are dead). This handle is used to shut down the service (and thus trigger process termination) once all child processes are also dead. A special option in the ARM configuration modifies the behaviour of the service implementation to not do the shutdown immediately.

Definition at line 274 of file gnunet-service-arm.c.

Referenced by add_service_handle(), callback_shutdown_service(), check_get(), check_set(), check_statistics_value(), check_watch(), close_service_room(), create_message_info(), create_message_peer(), create_service(), create_srv_handle(), destroy_service(), do_shutdown(), entry_service_room(), find_subsystem_entry(), free_service_record(), get_service_contact_store(), get_service_peer_identity(), get_service_room(), gns_string_to_value(), handle_get(), handle_service_message(), handle_set(), handle_statistics_value(), handle_watch(), init_peer_store(), open_service_room(), recv_message_miss(), remove_service_handle(), resolver_lookup_get_next_label(), run(), run(), run(), run(), run(), run(), run(), run(), run(), run(), sign_srv_room_message_by_peer(), srv_status(), and store_service().

◆ notifier

struct GNUNET_NotificationContext* notifier
static

Context for notifications we need to send to our clients.

Definition at line 279 of file gnunet-service-arm.c.

Referenced by broadcast_status(), do_shutdown(), handle_monitor(), and run().