GNUnet 0.26.2-114-g7c6b613e3
 
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_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 char *binary;
754
755 GNUNET_assert (NULL == sl->proc);
760 for (struct ServiceListeningInfo *sli = sl->listen_head;
761 NULL != sli;
762 sli = sli->next)
763 {
766 sl->proc,
768 GNUNET_NETWORK_get_fd (sli->listen_socket))));
769 if (NULL != sli->accept_task)
770 {
771 GNUNET_SCHEDULER_cancel (sli->accept_task);
772 sli->accept_task = NULL;
773 }
774 }
775
776 /* obtain configuration */
777 if (GNUNET_OK !=
779 sl->name,
780 "PREFIX",
781 &loprefix))
782 loprefix = GNUNET_strdup (prefix_command);
783 else
785 loprefix);
786 if (GNUNET_OK !=
788 sl->name,
789 "OPTIONS",
790 &options))
791 options = NULL;
792 else
794 {
795 char *new_options;
796 char *optpos;
797 char *fin_options;
798
799 fin_options = GNUNET_strdup (final_option);
800 /* replace '{}' with service name */
801 while (NULL != (optpos = strstr (fin_options, "{}")))
802 {
803 /* terminate string at opening parenthesis */
804 *optpos = 0;
805 GNUNET_asprintf (&new_options,
806 "%s%s%s",
807 fin_options,
808 sl->name,
809 optpos + 2);
810 GNUNET_free (fin_options);
811 fin_options = new_options;
812 }
813 if (NULL != options)
814 {
815 /* combine "fin_options" with "options" */
816 optpos = options;
818 "%s %s",
819 fin_options,
820 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 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);
863 "Starting simple service `%s' using binary `%s'\n",
864 sl->name,
865 sl->binary);
867 loprefix,
868 binary,
869 options,
870 NULL);
871 }
872 else
873 {
874 char *command;
875
876 /* actually start process */
878 "Starting service `%s' using binary `%s' and configuration `%s'\n",
879 sl->name,
880 sl->binary,
881 sl->config);
884 sl->binary);
885 GNUNET_asprintf (&command,
886 "%s%s%s%s%s%s%s%s",
887 loprefix,
888 (0 == strlen (loprefix)) ? "" : " ",
889 binary,
890 (use_debug) ? " -L DEBUG" : "",
891 (NULL == sl->config) ? "" : " -c ",
892 (NULL == sl->config) ? "" : sl->config,
893 (0 == strlen (options)) ? "" : " ",
894 options);
896 "Launching GNUnet service `%s'\n",
897 command);
899 sl->proc,
900 command);
901 GNUNET_free (command);
902 }
903
904 if (GNUNET_OK != ret)
905 {
906 GNUNET_break (0);
907 goto failure;
908 }
909
912 "Starting service `%s'\n",
913 sl->name);
916 NULL);
917 if (client)
918 signal_result (client,
919 sl->name,
920 request_id,
922 goto cleanup;
923failure:
924 if (NULL != sl->proc)
925 {
927 sl->proc = NULL;
928 }
930 "Failed to start service `%s'\n",
931 sl->name);
932 if (client)
933 signal_result (client,
934 sl->name,
935 request_id,
937cleanup:
938 GNUNET_free (binary);
939 GNUNET_free (loprefix);
941}
942
943
951static struct ServiceList *
952find_service (const char *name)
953{
954 struct ServiceList *sl;
955
956 sl = running_head;
957 while (sl != NULL)
958 {
959 if (0 == strcasecmp (sl->name, name))
960 return sl;
961 sl = sl->next;
962 }
963 return NULL;
964}
965
966
973static void
974accept_connection (void *cls)
975{
976 struct ServiceListeningInfo *sli = cls;
977 struct ServiceList *sl = sli->sl;
978
979 sli->accept_task = NULL;
981 start_process (sl, NULL, 0);
982}
983
984
993static void
994create_listen_socket (struct sockaddr *sa,
995 socklen_t addr_len,
996 struct ServiceList *sl)
997{
998 static int on = 1;
999 struct GNUNET_NETWORK_Handle *sock;
1000 struct ServiceListeningInfo *sli;
1001
1002 int match_uid;
1003 int match_gid;
1004
1005 switch (sa->sa_family)
1006 {
1007 case AF_INET:
1008 sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
1009 break;
1010
1011 case AF_INET6:
1012 sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1013 break;
1014
1015 case AF_UNIX:
1016 if (0 == strcmp (GNUNET_a2s (sa, addr_len),
1017 "@")) /* Do not bind to blank UNIX path! */
1018 return;
1019 sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
1020 break;
1021
1022 default:
1023 GNUNET_break (0);
1024 sock = NULL;
1025 errno = EAFNOSUPPORT;
1026 break;
1027 }
1028 if (NULL == sock)
1029 {
1031 _ ("Unable to create socket for service `%s': %s\n"),
1032 sl->name,
1033 strerror (errno));
1034 GNUNET_free (sa);
1035 return;
1036 }
1038 SOL_SOCKET,
1039 SO_REUSEADDR,
1040 &on,
1041 sizeof(on)))
1043 "setsockopt");
1044#ifdef IPV6_V6ONLY
1045 if ((sa->sa_family == AF_INET6) &&
1047 IPPROTO_IPV6,
1048 IPV6_V6ONLY,
1049 &on,
1050 sizeof(on))))
1052 "setsockopt");
1053#endif
1054 if (AF_UNIX == sa->sa_family)
1055 GNUNET_NETWORK_unix_precheck ((struct sockaddr_un *) sa);
1056 if (GNUNET_OK !=
1057 GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) sa, addr_len))
1058 {
1059 GNUNET_log (
1061 _ (
1062 "Unable to bind listening socket for service `%s' to address `%s': %s\n"),
1063 sl->name,
1064 GNUNET_a2s (sa, addr_len),
1065 strerror (errno));
1067 GNUNET_free (sa);
1068 return;
1069 }
1070 if ((AF_UNIX == sa->sa_family)
1071#ifdef __linux__
1072 /* Permission settings are not required when abstract sockets are used */
1073 && ('\0' != ((const struct sockaddr_un *) sa)->sun_path[0])
1074#endif
1075 )
1076 {
1077 match_uid =
1078 (GNUNET_YES ==
1080 sl->name,
1081 "UNIX_MATCH_UID"));
1082 match_gid =
1083 (GNUNET_YES ==
1085 sl->name,
1086 "UNIX_MATCH_GID"));
1087 GNUNET_DISK_fix_permissions (((const struct sockaddr_un *) sa)->sun_path,
1088 match_uid,
1089 match_gid);
1090 }
1091 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
1092 {
1095 GNUNET_free (sa);
1096 return;
1097 }
1099 _ ("ARM now monitors connections to service `%s' at `%s'\n"),
1100 sl->name,
1101 GNUNET_a2s (sa, addr_len));
1102 sli = GNUNET_new (struct ServiceListeningInfo);
1103 sli->service_addr = sa;
1104 sli->service_addr_len = addr_len;
1105 sli->listen_socket = sock;
1106 sli->sl = sl;
1107 sli->accept_task =
1109 sock,
1111 sli);
1113}
1114
1115
1122static void
1123free_service (struct ServiceList *sl)
1124{
1127 GNUNET_assert (NULL == sl->listen_head);
1130 GNUNET_free (sl->name);
1131 GNUNET_free (sl);
1132}
1133
1134
1143static int
1144check_start (void *cls, const struct GNUNET_ARM_Message *amsg)
1145{
1146 (void) cls;
1148 return GNUNET_OK;
1149}
1150
1151
1158static void
1159handle_start (void *cls, const struct GNUNET_ARM_Message *amsg)
1160{
1161 struct GNUNET_SERVICE_Client *client = cls;
1162 const char *servicename;
1163 struct ServiceList *sl;
1164 uint64_t request_id;
1165
1166 request_id = GNUNET_ntohll (amsg->request_id);
1167 servicename = (const char *) &amsg[1];
1169 if (GNUNET_YES == in_shutdown)
1170 {
1171 signal_result (client,
1172 servicename,
1173 request_id,
1175 return;
1176 }
1177 sl = find_service (servicename);
1178 if (NULL == sl)
1179 {
1180 signal_result (client,
1181 servicename,
1182 request_id,
1184 return;
1185 }
1186 sl->force_start = GNUNET_YES;
1187 if (NULL != sl->proc)
1188 {
1189 signal_result (client,
1190 servicename,
1191 request_id,
1193 return;
1194 }
1195 start_process (sl, client, request_id);
1196}
1197
1198
1204static void
1205trigger_shutdown (void *cls)
1206{
1207 (void) cls;
1208 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Triggering shutdown\n");
1210}
1211
1212
1221static int
1222check_stop (void *cls,
1223 const struct GNUNET_ARM_Message *amsg)
1224{
1225 (void) cls;
1227 return GNUNET_OK;
1228}
1229
1230
1237static void
1238handle_stop (void *cls,
1239 const struct GNUNET_ARM_Message *amsg)
1240{
1241 struct GNUNET_SERVICE_Client *client = cls;
1242 struct ServiceList *sl;
1243 const char *servicename;
1244 uint64_t request_id;
1245
1246 request_id = GNUNET_ntohll (amsg->request_id);
1247 servicename = (const char *) &amsg[1];
1249 _ ("Preparing to stop `%s'\n"),
1250 servicename);
1252 if (0 == strcasecmp (servicename, "arm"))
1253 {
1254 broadcast_status (servicename, GNUNET_ARM_SERVICE_STOPPING, NULL);
1255 signal_result (client,
1256 servicename,
1257 request_id,
1261 return;
1262 }
1263 sl = find_service (servicename);
1264 if (NULL == sl)
1265 {
1266 signal_result (client,
1267 servicename,
1268 request_id,
1270 return;
1271 }
1272 sl->force_start = GNUNET_NO;
1273 if (GNUNET_YES == in_shutdown)
1274 {
1275 /* shutdown in progress */
1276 signal_result (client,
1277 servicename,
1278 request_id,
1280 return;
1281 }
1282 if (NULL != sl->killing_client)
1283 {
1284 /* killing already in progress */
1285 signal_result (client,
1286 servicename,
1287 request_id,
1289 return;
1290 }
1291 if (NULL == sl->proc)
1292 {
1293 /* process is down */
1294 signal_result (client,
1295 servicename,
1296 request_id,
1298 return;
1299 }
1301 "Sending kill signal to service `%s', waiting for process to die.\n",
1302 servicename);
1303 broadcast_status (servicename,
1305 NULL);
1306 /* no signal_start - only when it's STOPPED */
1308 if (GNUNET_OK !=
1312 "kill");
1313 sl->killing_client = client;
1314 sl->killing_client_request_id = request_id;
1315}
1316
1317
1329static int
1330pool_write (char *pool_start, size_t pool_size, size_t *pool_pos, char *str)
1331{
1332 size_t next_pos = (*pool_pos) + strlen (str) + 1;
1333
1334 if (next_pos > pool_size)
1335 return GNUNET_SYSERR;
1336 memcpy (pool_start + *pool_pos, str, strlen (str) + 1);
1337 *pool_pos = next_pos;
1338 return GNUNET_OK;
1339}
1340
1341
1348static void
1349handle_list (void *cls, const struct GNUNET_ARM_Message *request)
1350{
1351 struct GNUNET_SERVICE_Client *client = cls;
1352 struct GNUNET_MQ_Envelope *env;
1354 size_t extra_size;
1355 struct ServiceList *sl;
1356 uint16_t count;
1357 size_t pool_size;
1358 size_t pool_pos;
1359 char *pool_start;
1361
1362 GNUNET_break_op (0 == ntohl (request->reserved));
1363 count = 0;
1364 pool_size = 0;
1365
1366 /* Do one pass over the list to compute the number of services
1367 * and the string pool size */
1368 for (sl = running_head; NULL != sl; sl = sl->next)
1369 {
1370 pool_size += strlen (sl->name) + 1;
1371 pool_size += strlen (sl->binary) + 1;
1372 count++;
1373 }
1374
1375 extra_size = pool_size + (count * sizeof (struct
1378 extra_size,
1380 msg->arm_msg.request_id = request->request_id;
1381 msg->count = htons (count);
1382
1383 ssm = (struct GNUNET_ARM_ServiceInfoMessage *) &msg[1];
1384 pool_start = (char *) (ssm + count);
1385 pool_pos = 0;
1386
1387 for (sl = running_head; NULL != sl; sl = sl->next)
1388 {
1389 ssm->name_index = htons ((uint16_t) pool_pos);
1390 GNUNET_assert (GNUNET_OK == pool_write (pool_start, pool_size, &pool_pos,
1391 sl->name));
1392 ssm->binary_index = htons ((uint16_t) pool_pos);
1393 GNUNET_assert (GNUNET_OK == pool_write (pool_start, pool_size, &pool_pos,
1394 sl->binary));
1395 if (NULL == sl->proc)
1396 {
1397 if (0 == sl->last_started_at.abs_value_us)
1398 {
1399 /* Process never started */
1401 }
1402 else if (0 == sl->last_exit_status)
1403 {
1405 }
1406 else
1407 {
1409 ssm->last_exit_status = htons (sl->last_exit_status);
1410 }
1411 }
1412 else if ((NULL != sl->killing_client) || (GNUNET_YES == in_shutdown))
1413 {
1415 }
1416 else
1417 {
1419 }
1422 ssm++;
1423 }
1426}
1427
1428
1435static void
1436handle_test (void *cls, const struct GNUNET_MessageHeader *message)
1437{
1438 struct GNUNET_SERVICE_Client *client = cls;
1439 struct GNUNET_MQ_Envelope *env;
1440 struct GNUNET_MessageHeader *msg;
1441
1442 (void) message;
1446}
1447
1448
1453static void
1454do_shutdown ()
1455{
1456 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Last shutdown phase\n");
1457 if (NULL != notifier)
1458 {
1460 notifier = NULL;
1461 }
1462 if (NULL != service)
1463 {
1465 service = NULL;
1466 }
1467 if (NULL != child_death_task)
1468 {
1470 child_death_task = NULL;
1471 }
1472}
1473
1474
1481static unsigned int
1482list_count (struct ServiceList *run_head)
1483{
1484 struct ServiceList *i;
1485 unsigned int res;
1486
1487 for (res = 0, i = run_head; NULL != i; i = i->next, res++)
1489 return res;
1490}
1491
1492
1498static void
1499shutdown_task (void *cls)
1500{
1501 struct ServiceList *pos;
1502 struct ServiceList *nxt;
1503 struct ServiceListeningInfo *sli;
1504
1505 (void) cls;
1506 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "First shutdown phase\n");
1507 if (NULL != child_restart_task)
1508 {
1510 child_restart_task = NULL;
1511 }
1513 /* first, stop listening */
1514 for (pos = running_head; NULL != pos; pos = pos->next)
1515 {
1516 while (NULL != (sli = pos->listen_head))
1517 {
1519 pos->listen_tail,
1520 sli);
1521 if (NULL != sli->accept_task)
1522 {
1524 sli->accept_task = NULL;
1525 }
1529 GNUNET_free (sli);
1530 }
1531 }
1532 /* then, shutdown all existing service processes */
1533 nxt = running_head;
1534 while (NULL != (pos = nxt))
1535 {
1536 nxt = pos->next;
1537 if (NULL != pos->proc)
1538 {
1540 "Stopping service `%s'\n",
1541 pos->name);
1543 if (GNUNET_OK !=
1547 "kill");
1548 }
1549 else
1550 {
1551 free_service (pos);
1552 }
1553 }
1554 /* finally, should all service processes be already gone, terminate for real */
1555 if (NULL == running_head)
1556 do_shutdown ();
1557 else
1559 "Delaying shutdown, have %u children still running\n",
1561}
1562
1563
1569static void
1570delayed_restart_task (void *cls)
1571
1572{
1573 struct ServiceList *sl;
1574 struct GNUNET_TIME_Relative lowestRestartDelay;
1575 struct ServiceListeningInfo *sli;
1576
1577 (void) cls;
1578 child_restart_task = NULL;
1580 lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL;
1581
1582 /* check for services that need to be restarted due to
1583 * configuration changes or because the last restart failed */
1584 for (sl = running_head; NULL != sl; sl = sl->next)
1585 {
1586 if (NULL != sl->proc)
1587 continue;
1588 /* service is currently not running */
1590 {
1591 /* restart is now allowed */
1592 if (sl->force_start)
1593 {
1594 /* process should run by default, start immediately */
1596 _ ("Restarting service `%s'.\n"),
1597 sl->name);
1598 start_process (sl, NULL, 0);
1599 }
1600 else
1601 {
1602 /* process is run on-demand, ensure it is re-started if there is demand */
1603 for (sli = sl->listen_head; NULL != sli; sli = sli->next)
1604 if (NULL == sli->accept_task)
1605 {
1606 /* accept was actually paused, so start it again */
1607 sli->accept_task =
1609 sli->listen_socket,
1611 sli);
1612 }
1613 }
1614 }
1615 else
1616 {
1617 /* update calculation for earliest time to reactivate a service */
1618 lowestRestartDelay =
1619 GNUNET_TIME_relative_min (lowestRestartDelay,
1621 sl->restart_at));
1622 }
1623 }
1624 if (lowestRestartDelay.rel_value_us !=
1625 GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1626 {
1628 "Will restart process in %s\n",
1629 GNUNET_STRINGS_relative_time_to_string (lowestRestartDelay,
1630 GNUNET_YES));
1635 NULL);
1636 }
1637}
1638
1639
1646static void
1647maint_child_death (void *cls)
1648{
1649 struct ServiceList *pos;
1650 struct ServiceList *next;
1651 struct ServiceListeningInfo *sli;
1652 const char *statstr;
1653 int statcode;
1654 int ret;
1655 char c[16];
1656 enum GNUNET_OS_ProcessStatusType statusType;
1657 unsigned long statusCode;
1658 const struct GNUNET_DISK_FileHandle *pr;
1659
1660 (void) cls;
1663 child_death_task = NULL;
1664 /* consume the signal */
1665 GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof(c)));
1666
1667 /* check for services that died (WAITPID) */
1668 next = running_head;
1669 while (NULL != (pos = next))
1670 {
1671 next = pos->next;
1672
1673 if (NULL == pos->proc)
1674 {
1675 if (GNUNET_YES == in_shutdown)
1676 free_service (pos);
1677 continue;
1678 }
1679#if HAVE_WAIT4
1680 if (NULL != wait_file)
1681 {
1682 /* need to use 'wait4()' to obtain and log performance data */
1683 struct rusage ru;
1684 int status;
1685 pid_t pid;
1686
1688 ret = wait4 (pid,
1689 &status,
1690 WNOHANG,
1691 &ru);
1692 if (ret <= 0)
1693 continue; /* no process done */
1694 if (WIFEXITED (status))
1695 {
1696 statusType = GNUNET_OS_PROCESS_EXITED;
1697 statusCode = WEXITSTATUS (status);
1698 }
1699 else if (WIFSIGNALED (status))
1700 {
1701 statusType = GNUNET_OS_PROCESS_SIGNALED;
1702 statusCode = WTERMSIG (status);
1703 }
1704 else if (WIFSTOPPED (status))
1705 {
1706 statusType = GNUNET_OS_PROCESS_SIGNALED;
1707 statusCode = WSTOPSIG (status);
1708 }
1709#ifdef WIFCONTINUED
1710 else if (WIFCONTINUED (status))
1711 {
1712 statusType = GNUNET_OS_PROCESS_RUNNING;
1713 statusCode = 0;
1714 }
1715#endif
1716 else
1717 {
1718 statusType = GNUNET_OS_PROCESS_UNKNOWN;
1719 statusCode = 0;
1720 }
1721 if ((GNUNET_OS_PROCESS_EXITED == statusType) ||
1722 (GNUNET_OS_PROCESS_SIGNALED == statusType))
1723 {
1724 double utime = ru.ru_utime.tv_sec + (ru.ru_utime.tv_usec / 10e6);
1725 double stime = ru.ru_stime.tv_sec + (ru.ru_stime.tv_usec / 10e6);
1726 fprintf (wait_file,
1727 "%s(%u) %.3f %.3f %llu %llu %llu %llu %llu\n",
1728 pos->binary,
1729 (unsigned int) pid,
1730 utime,
1731 stime,
1732 (unsigned long long) ru.ru_maxrss,
1733 (unsigned long long) ru.ru_inblock,
1734 (unsigned long long) ru.ru_oublock,
1735 (unsigned long long) ru.ru_nvcsw,
1736 (unsigned long long) ru.ru_nivcsw);
1737 }
1738 }
1739 else /* continue with JUST this "if" as "else" (intentionally no brackets!) */
1740#endif
1741 if ((GNUNET_SYSERR ==
1742 (ret = GNUNET_process_wait (pos->proc,
1743 false,
1744 &statusType,
1745 &statusCode))) ||
1746 (ret == GNUNET_NO) ||
1747 (statusType == GNUNET_OS_PROCESS_STOPPED) ||
1748 (statusType == GNUNET_OS_PROCESS_UNKNOWN) ||
1749 (statusType == GNUNET_OS_PROCESS_RUNNING))
1750 continue;
1751
1752 if (statusType == GNUNET_OS_PROCESS_EXITED)
1753 {
1754 statstr = _ (/* process termination method */ "exit");
1755 statcode = statusCode;
1756 }
1757 else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
1758 {
1759 statstr = _ (/* process termination method */ "signal");
1760 statcode = statusCode;
1761 }
1762 else
1763 {
1764 statstr = _ (/* process termination method */ "unknown");
1765 statcode = 0;
1766 }
1767 if (0 != pos->killed_at.abs_value_us)
1768 {
1770 _ ("Service `%s' took %s to terminate\n"),
1771 pos->name,
1774 GNUNET_YES));
1775 }
1777 pos->proc = NULL;
1778 broadcast_status (pos->name,
1780 NULL);
1781 if (NULL != pos->killing_client)
1782 {
1784 pos->name,
1787 pos->killing_client = NULL;
1789 }
1790 if (GNUNET_YES != in_shutdown)
1791 {
1792 pos->last_exit_status = statcode;
1793 if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0))
1794 {
1795 /* process terminated normally, allow restart at any time */
1796 pos->restart_at.abs_value_us = 0;
1797 GNUNET_log (
1799 _ ("Service `%s' terminated normally, will restart at any time\n"),
1800 pos->name);
1801 /* process can still be re-started on-demand, ensure it is re-started if there is demand */
1802 for (sli = pos->listen_head; NULL != sli; sli = sli->next)
1803 {
1804 GNUNET_break (NULL == sli->accept_task);
1805 sli->accept_task =
1807 sli->listen_socket,
1809 sli);
1810 }
1811 }
1812 else
1813 {
1814 GNUNET_log (
1816 _ ("Service `%s' terminated with status %s/%d, will restart in %s\n"),
1817 pos->name,
1818 statstr,
1819 statcode,
1821 {
1822 /* Reduce backoff based on runtime of the process,
1823 so that there is a cool-down if a process actually
1824 runs for a while. */
1825 struct GNUNET_TIME_Relative runtime;
1826 unsigned int minutes;
1827
1829 minutes =
1830 runtime.rel_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us;
1831 if (minutes > 31)
1833 else
1834 pos->backoff.rel_value_us >>= minutes;
1835 }
1836 /* schedule restart */
1839 if (NULL != child_restart_task)
1844 NULL);
1845 }
1846 }
1847 else
1848 {
1849 free_service (pos);
1850 }
1851 }
1854 pr,
1856 NULL);
1857 if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
1858 do_shutdown ();
1859 else if (GNUNET_YES == in_shutdown)
1861 "Delaying shutdown after child's death, still have %u children\n",
1863}
1864
1865
1870static void
1872{
1873 static char c;
1874 int old_errno = errno; /* back-up errno */
1875
1876 GNUNET_break (
1877 1 ==
1880 ,
1881 &c,
1882 sizeof(c)));
1883 errno = old_errno; /* restore errno */
1884}
1885
1886
1895static void
1896setup_service (void *cls,
1897 const char *section)
1898{
1899 struct ServiceList *sl;
1900 char *binary;
1901 char *config;
1902 struct stat sbuf;
1903 struct sockaddr **addrs;
1904 socklen_t *addr_lens;
1905 int ret;
1906
1907 (void) cls;
1908 if (0 == strcasecmp (section, "arm"))
1909 return;
1910 if (GNUNET_OK !=
1912 section,
1913 "BINARY",
1914 &binary))
1915 {
1916 /* not a service section */
1917 return;
1918 }
1919 if (GNUNET_YES ==
1921 section,
1922 "RUN_PER_USER"))
1923 {
1924 if (GNUNET_NO == start_user)
1925 {
1926 GNUNET_free (binary);
1927 return; /* user service, and we don't deal with those */
1928 }
1929 }
1930 else
1931 {
1932 if (GNUNET_NO == start_system)
1933 {
1934 GNUNET_free (binary);
1935 return; /* system service, and we don't deal with those */
1936 }
1937 }
1938 sl = find_service (section);
1939 if (NULL != sl)
1940 {
1941 /* got the same section twice!? */
1942 GNUNET_break (0);
1943 GNUNET_free (binary);
1944 return;
1945 }
1946 config = NULL;
1947 if (((GNUNET_OK !=
1949 section,
1950 "CONFIG",
1951 &config)) &&
1952 (GNUNET_OK !=
1954 "PATHS",
1955 "DEFAULTCONFIG",
1956 &config))) ||
1957 (0 != stat (config,
1958 &sbuf)))
1959 {
1960 if (NULL != config)
1961 {
1963 section,
1964 "CONFIG",
1965 strerror (errno));
1967 config = NULL;
1968 }
1969 }
1970 sl = GNUNET_new (struct ServiceList);
1971 sl->name = GNUNET_strdup (section);
1972 sl->binary = binary;
1973 sl->config = config;
1976 sl->pipe_control =
1977 (GNUNET_YES ==
1979 section,
1980 "PIPECONTROL"));
1983 sl);
1984 if (GNUNET_YES ==
1986 section,
1987 "IMMEDIATE_START"))
1988 {
1989 sl->force_start = GNUNET_YES;
1990 if (GNUNET_YES ==
1992 section,
1993 "NOARMBIND"))
1994 return;
1995 }
1996 else
1997 {
1998 if (GNUNET_YES !=
2000 section,
2001 "START_ON_DEMAND"))
2002 return;
2003 }
2004 if (0 >= (ret = get_server_addresses (section,
2005 cfg,
2006 &addrs,
2007 &addr_lens)))
2008 return;
2009 /* this will free (or capture) addrs[i] */
2010 for (unsigned int i = 0; i < (unsigned int) ret; i++)
2011 create_listen_socket (addrs[i], addr_lens[i], sl);
2012 GNUNET_free (addrs);
2013 GNUNET_free (addr_lens);
2014}
2015
2016
2025static void *
2026client_connect_cb (void *cls,
2027 struct GNUNET_SERVICE_Client *client,
2028 struct GNUNET_MQ_Handle *mq)
2029{
2030 /* All clients are considered to be of the "monitor" kind
2031 * (that is, they don't affect ARM shutdown).
2032 */
2033 (void) cls;
2034 (void) mq;
2036 return client;
2037}
2038
2039
2047static void
2048client_disconnect_cb (void *cls,
2049 struct GNUNET_SERVICE_Client *client,
2050 void *app_ctx)
2051{
2052 (void) cls;
2053 GNUNET_assert (client == app_ctx);
2054 for (struct ServiceList *sl = running_head; NULL != sl; sl = sl->next)
2055 if (sl->killing_client == client)
2056 sl->killing_client = NULL;
2057}
2058
2059
2068static void
2069handle_monitor (void *cls,
2070 const struct GNUNET_MessageHeader *message)
2071{
2072 struct GNUNET_SERVICE_Client *client = cls;
2073
2074 (void) message;
2075 /* FIXME: might want to start by letting monitor know about
2076 services that are already running */
2077 /* Removal is handled by the server implementation, internally. */
2080 broadcast_status ("arm",
2082 client);
2084}
2085
2086
2094static void
2095run (void *cls,
2096 const struct GNUNET_CONFIGURATION_Handle *c,
2097 struct GNUNET_SERVICE_Handle *serv)
2098{
2099 struct ServiceList *sl;
2100 enum GNUNET_GenericReturnValue ret1;
2101 enum GNUNET_GenericReturnValue ret2;
2102
2103 (void) cls;
2104 cfg = c;
2105 service = serv;
2107 NULL);
2113 NULL);
2114#if HAVE_WAIT4
2115 if (GNUNET_OK ==
2117 "ARM",
2118 "RESOURCE_DIAGNOSTICS",
2119 &wait_filename))
2120 {
2121 wait_file = fopen (wait_filename, "w");
2122 if (NULL == wait_file)
2123 {
2125 "fopen",
2126 wait_filename);
2127 }
2128 }
2129#endif
2130 if (GNUNET_OK !=
2132 "ARM",
2133 "GLOBAL_PREFIX",
2136 else
2139 if (GNUNET_OK !=
2141 "ARM",
2142 "GLOBAL_POSTFIX",
2143 &final_option))
2145 else
2147 final_option);
2149 "ARM",
2150 "START_SYSTEM_SERVICES");
2152 "ARM",
2153 "START_USER_SERVICES");
2154 if ( (GNUNET_SYSERR == ret1) ||
2155 (GNUNET_SYSERR == ret2) )
2156 {
2157 /* invalid option */
2158 GNUNET_break (0);
2160 global_ret = 1;
2161 return;
2162 }
2164 "ARM",
2165 "START_SYSTEM_SERVICES"))
2166 ret1 = GNUNET_SYSERR;
2168 "ARM",
2169 "START_USER_SERVICES"))
2170 ret2 = GNUNET_SYSERR;
2171 start_system = (GNUNET_YES == ret1) ||
2172 ( (GNUNET_SYSERR == ret1) && (GNUNET_SYSERR == ret2) );
2173 start_user = (GNUNET_YES == ret2) ||
2174 ( (GNUNET_SYSERR == ret1) && (GNUNET_SYSERR == ret2) );
2175 if ( (GNUNET_NO == start_user) &&
2176 (GNUNET_NO == start_system) )
2177 {
2178 GNUNET_log (
2180 "Please enable either START_USER_SERVICES or START_SYSTEM_SERVICES\n");
2182 global_ret = 1;
2183 return;
2184 }
2187 NULL);
2188
2189 /* start default services... */
2190 for (sl = running_head; NULL != sl; sl = sl->next)
2191 if (GNUNET_YES == sl->force_start)
2192 start_process (sl, NULL, 0);
2194}
2195
2196
2204int
2205main (int argc, char *const *argv)
2206{
2211 struct GNUNET_ARM_Message,
2212 NULL),
2215 struct GNUNET_ARM_Message,
2216 NULL),
2219 struct GNUNET_MessageHeader,
2220 NULL),
2223 struct GNUNET_ARM_Message,
2224 NULL),
2227 struct GNUNET_MessageHeader,
2228 NULL),
2230 };
2231
2233 GNUNET_assert (NULL != sigpipe);
2234 shc_chld =
2237 if (0 !=
2239 argc,
2240 argv,
2241 "arm",
2244 &run,
2247 NULL,
2248 handlers))
2249 global_ret = 2;
2250#if HAVE_WAIT4
2251 if (NULL != wait_file)
2252 {
2253 fclose (wait_file);
2254 wait_file = NULL;
2255 }
2256 if (NULL != wait_filename)
2257 {
2258 GNUNET_free (wait_filename);
2259 wait_filename = NULL;
2260 }
2261#endif
2263 shc_chld = NULL;
2265 sigpipe = NULL;
2266 return global_ret;
2267}
2268
2269
2270#if defined(__linux__) && defined(__GLIBC__)
2271#include <malloc.h>
2272
2273void __attribute__ ((constructor))
2274GNUNET_ARM_memory_init (void);
2275
2279void __attribute__ ((constructor))
2280GNUNET_ARM_memory_init (void)
2281{
2282 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2283 mallopt (M_TOP_PAD, 1 * 1024);
2284 malloc_trim (0);
2285}
2286
2287
2288#endif
2289
2290
2291/* 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 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 void cleanup()
Cleanup task.
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:1703
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:745
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(enum GNUNET_DISK_PipeFlags pf)
Creates an interprocess channel.
Definition disk.c:1524
enum GNUNET_GenericReturnValue GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition disk.c:1671
enum GNUNET_GenericReturnValue GNUNET_DISK_directory_create_for_file(const char *filename)
Create the directory structure for storing a file.
Definition disk.c:664
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:704
@ 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_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_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:1000
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:832
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:651
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:805
const struct GNUNET_OS_ProjectData * GNUNET_OS_project_data_gnunet(void)
Return default project data used by 'libgnunetutil' for GNUnet.
#define GNUNET_process_option_inherit_lsock(lsock)
Pass listen socket to child systemd-style.
enum GNUNET_GenericReturnValue GNUNET_process_run_command_va(struct GNUNET_Process *p, const char *filename,...)
Set the command and start a process.
Definition os_process.c:903
enum GNUNET_GenericReturnValue GNUNET_process_run_command(struct GNUNET_Process *p, const char *command)
Set the command and start a process.
Definition os_process.c:921
enum GNUNET_GenericReturnValue GNUNET_process_wait(struct GNUNET_Process *proc, bool blocking, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code)
Wait for a process to terminate.
void GNUNET_process_destroy(struct GNUNET_Process *proc)
Cleans up process structure contents (OS-dependent) and deallocates it.
Definition os_process.c:363
#define GNUNET_process_set_options(proc,...)
Set the requested options for the process.
GNUNET_OS_ProcessStatusType
Process status types.
pid_t GNUNET_process_get_pid(const struct GNUNET_Process *proc)
Get the pid of the process in question.
Definition os_process.c:356
enum GNUNET_GenericReturnValue GNUNET_process_kill(struct GNUNET_Process *proc, int sig)
Sends a signal to the process.
Definition os_process.c:307
struct GNUNET_Process * GNUNET_process_create(enum GNUNET_OS_InheritStdioFlags std_inheritance)
Create a process handle.
Definition os_process.c:462
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:572
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:1517
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:1667
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:1345
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition scheduler.c:986
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:1310
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:1213
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:1237
void GNUNET_SERVICE_shutdown(struct GNUNET_SERVICE_Handle *sh)
Explicitly stops the service.
Definition service.c:2512
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:2022
void GNUNET_SERVICE_client_mark_monitor(struct GNUNET_SERVICE_Client *c)
Set the 'monitor' flag on this client.
Definition service.c:2528
void GNUNET_SERVICE_client_persist(struct GNUNET_SERVICE_Client *c)
Set the persist option on this client.
Definition service.c:2538
struct GNUNET_MQ_Handle * GNUNET_SERVICE_client_get_mq(struct GNUNET_SERVICE_Client *c)
Obtain the message queue of c.
Definition service.c:2545
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition service.c:2434
@ 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:604
#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:636
#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:141
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).
struct GNUNET_Process * proc
Process structure pointer of the child.
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_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.
const char * str
Definition time.c:1252

◆ 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 char *binary;
755
756 GNUNET_assert (NULL == sl->proc);
761 for (struct ServiceListeningInfo *sli = sl->listen_head;
762 NULL != sli;
763 sli = sli->next)
764 {
767 sl->proc,
769 GNUNET_NETWORK_get_fd (sli->listen_socket))));
770 if (NULL != sli->accept_task)
771 {
772 GNUNET_SCHEDULER_cancel (sli->accept_task);
773 sli->accept_task = NULL;
774 }
775 }
776
777 /* obtain configuration */
778 if (GNUNET_OK !=
780 sl->name,
781 "PREFIX",
782 &loprefix))
783 loprefix = GNUNET_strdup (prefix_command);
784 else
786 loprefix);
787 if (GNUNET_OK !=
789 sl->name,
790 "OPTIONS",
791 &options))
792 options = NULL;
793 else
795 {
796 char *new_options;
797 char *optpos;
798 char *fin_options;
799
800 fin_options = GNUNET_strdup (final_option);
801 /* replace '{}' with service name */
802 while (NULL != (optpos = strstr (fin_options, "{}")))
803 {
804 /* terminate string at opening parenthesis */
805 *optpos = 0;
806 GNUNET_asprintf (&new_options,
807 "%s%s%s",
808 fin_options,
809 sl->name,
810 optpos + 2);
811 GNUNET_free (fin_options);
812 fin_options = new_options;
813 }
814 if (NULL != options)
815 {
816 /* combine "fin_options" with "options" */
817 optpos = options;
819 "%s %s",
820 fin_options,
821 optpos);
822 GNUNET_free (fin_options);
823 GNUNET_free (optpos);
824 }
825 else
826 {
827 /* only have "fin_options", use that */
828 options = fin_options;
829 }
830 }
832 options);
834 sl->name,
835 "DEBUG");
836 {
837 const char *service_type = NULL;
838 const char *choices[] = {
839 "GNUNET",
840 "SIMPLE",
841 NULL
842 };
843
844 is_simple_service = false;
845 if ( (GNUNET_OK ==
847 sl->name,
848 "TYPE",
849 choices,
850 &service_type)) &&
851 (0 == strcasecmp (service_type,
852 "SIMPLE")) )
853 is_simple_service = true;
854 }
855
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);
864 "Starting simple service `%s' using binary `%s'\n",
865 sl->name,
866 sl->binary);
868 loprefix,
869 binary,
870 options,
871 NULL);
872 }
873 else
874 {
875 char *command;
876
877 /* actually start process */
879 "Starting service `%s' using binary `%s' and configuration `%s'\n",
880 sl->name,
881 sl->binary,
882 sl->config);
885 sl->binary);
886 GNUNET_asprintf (&command,
887 "%s%s%s%s%s%s%s%s",
888 loprefix,
889 (0 == strlen (loprefix)) ? "" : " ",
890 binary,
891 (use_debug) ? " -L DEBUG" : "",
892 (NULL == sl->config) ? "" : " -c ",
893 (NULL == sl->config) ? "" : sl->config,
894 (0 == strlen (options)) ? "" : " ",
895 options);
897 "Launching GNUnet service `%s'\n",
898 command);
900 sl->proc,
901 command);
902 GNUNET_free (command);
903 }
904
905 if (GNUNET_OK != ret)
906 {
907 GNUNET_break (0);
908 goto failure;
909 }
910
913 "Starting service `%s'\n",
914 sl->name);
917 NULL);
918 if (client)
919 signal_result (client,
920 sl->name,
921 request_id,
923 goto cleanup;
924failure:
925 if (NULL != sl->proc)
926 {
928 sl->proc = NULL;
929 }
931 "Failed to start service `%s'\n",
932 sl->name);
933 if (client)
934 signal_result (client,
935 sl->name,
936 request_id,
938cleanup:
939 GNUNET_free (binary);
940 GNUNET_free (loprefix);
942}

References ServiceList::binary, broadcast_status(), cfg, cleanup(), ServiceList::config, final_option, GNUNET_ARM_RESULT_START_FAILED, GNUNET_ARM_RESULT_STARTING, GNUNET_ARM_SERVICE_STARTING, GNUNET_asprintf(), GNUNET_assert, GNUNET_break, 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_USE_PIPE_CONTROL, GNUNET_process_create(), GNUNET_process_destroy(), GNUNET_process_option_inherit_lsock, GNUNET_process_run_command(), GNUNET_process_run_command_va(), GNUNET_process_set_options, GNUNET_SCHEDULER_cancel(), GNUNET_strdup, GNUNET_TIME_absolute_get(), ServiceList::last_started_at, ServiceList::listen_head, ServiceList::name, options, ServiceList::pipe_control, prefix_command, ServiceList::proc, ret, 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 953 of file gnunet-service-arm.c.

954{
955 struct ServiceList *sl;
956
957 sl = running_head;
958 while (sl != NULL)
959 {
960 if (0 == strcasecmp (sl->name, name))
961 return sl;
962 sl = sl->next;
963 }
964 return NULL;
965}

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 975 of file gnunet-service-arm.c.

976{
977 struct ServiceListeningInfo *sli = cls;
978 struct ServiceList *sl = sli->sl;
979
980 sli->accept_task = NULL;
982 start_process (sl, NULL, 0);
983}

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 995 of file gnunet-service-arm.c.

998{
999 static int on = 1;
1000 struct GNUNET_NETWORK_Handle *sock;
1001 struct ServiceListeningInfo *sli;
1002
1003 int match_uid;
1004 int match_gid;
1005
1006 switch (sa->sa_family)
1007 {
1008 case AF_INET:
1009 sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
1010 break;
1011
1012 case AF_INET6:
1013 sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1014 break;
1015
1016 case AF_UNIX:
1017 if (0 == strcmp (GNUNET_a2s (sa, addr_len),
1018 "@")) /* Do not bind to blank UNIX path! */
1019 return;
1020 sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
1021 break;
1022
1023 default:
1024 GNUNET_break (0);
1025 sock = NULL;
1026 errno = EAFNOSUPPORT;
1027 break;
1028 }
1029 if (NULL == sock)
1030 {
1032 _ ("Unable to create socket for service `%s': %s\n"),
1033 sl->name,
1034 strerror (errno));
1035 GNUNET_free (sa);
1036 return;
1037 }
1039 SOL_SOCKET,
1040 SO_REUSEADDR,
1041 &on,
1042 sizeof(on)))
1044 "setsockopt");
1045#ifdef IPV6_V6ONLY
1046 if ((sa->sa_family == AF_INET6) &&
1048 IPPROTO_IPV6,
1049 IPV6_V6ONLY,
1050 &on,
1051 sizeof(on))))
1053 "setsockopt");
1054#endif
1055 if (AF_UNIX == sa->sa_family)
1056 GNUNET_NETWORK_unix_precheck ((struct sockaddr_un *) sa);
1057 if (GNUNET_OK !=
1058 GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) sa, addr_len))
1059 {
1060 GNUNET_log (
1062 _ (
1063 "Unable to bind listening socket for service `%s' to address `%s': %s\n"),
1064 sl->name,
1065 GNUNET_a2s (sa, addr_len),
1066 strerror (errno));
1068 GNUNET_free (sa);
1069 return;
1070 }
1071 if ((AF_UNIX == sa->sa_family)
1072#ifdef __linux__
1073 /* Permission settings are not required when abstract sockets are used */
1074 && ('\0' != ((const struct sockaddr_un *) sa)->sun_path[0])
1075#endif
1076 )
1077 {
1078 match_uid =
1079 (GNUNET_YES ==
1081 sl->name,
1082 "UNIX_MATCH_UID"));
1083 match_gid =
1084 (GNUNET_YES ==
1086 sl->name,
1087 "UNIX_MATCH_GID"));
1088 GNUNET_DISK_fix_permissions (((const struct sockaddr_un *) sa)->sun_path,
1089 match_uid,
1090 match_gid);
1091 }
1092 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
1093 {
1096 GNUNET_free (sa);
1097 return;
1098 }
1100 _ ("ARM now monitors connections to service `%s' at `%s'\n"),
1101 sl->name,
1102 GNUNET_a2s (sa, addr_len));
1103 sli = GNUNET_new (struct ServiceListeningInfo);
1104 sli->service_addr = sa;
1105 sli->service_addr_len = addr_len;
1106 sli->listen_socket = sock;
1107 sli->sl = sl;
1108 sli->accept_task =
1110 sock,
1112 sli);
1114}

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 1124 of file gnunet-service-arm.c.

1125{
1128 GNUNET_assert (NULL == sl->listen_head);
1129 GNUNET_free (sl->config);
1130 GNUNET_free (sl->binary);
1131 GNUNET_free (sl->name);
1132 GNUNET_free (sl);
1133}

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 1145 of file gnunet-service-arm.c.

1146{
1147 (void) cls;
1149 return GNUNET_OK;
1150}

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 1160 of file gnunet-service-arm.c.

1161{
1162 struct GNUNET_SERVICE_Client *client = cls;
1163 const char *servicename;
1164 struct ServiceList *sl;
1165 uint64_t request_id;
1166
1167 request_id = GNUNET_ntohll (amsg->request_id);
1168 servicename = (const char *) &amsg[1];
1170 if (GNUNET_YES == in_shutdown)
1171 {
1172 signal_result (client,
1173 servicename,
1174 request_id,
1176 return;
1177 }
1178 sl = find_service (servicename);
1179 if (NULL == sl)
1180 {
1181 signal_result (client,
1182 servicename,
1183 request_id,
1185 return;
1186 }
1187 sl->force_start = GNUNET_YES;
1188 if (NULL != sl->proc)
1189 {
1190 signal_result (client,
1191 servicename,
1192 request_id,
1194 return;
1195 }
1196 start_process (sl, client, request_id);
1197}

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 1206 of file gnunet-service-arm.c.

1207{
1208 (void) cls;
1209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Triggering shutdown\n");
1211}

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 1223 of file gnunet-service-arm.c.

1225{
1226 (void) cls;
1228 return GNUNET_OK;
1229}

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 1239 of file gnunet-service-arm.c.

1241{
1242 struct GNUNET_SERVICE_Client *client = cls;
1243 struct ServiceList *sl;
1244 const char *servicename;
1245 uint64_t request_id;
1246
1247 request_id = GNUNET_ntohll (amsg->request_id);
1248 servicename = (const char *) &amsg[1];
1250 _ ("Preparing to stop `%s'\n"),
1251 servicename);
1253 if (0 == strcasecmp (servicename, "arm"))
1254 {
1255 broadcast_status (servicename, GNUNET_ARM_SERVICE_STOPPING, NULL);
1256 signal_result (client,
1257 servicename,
1258 request_id,
1262 return;
1263 }
1264 sl = find_service (servicename);
1265 if (NULL == sl)
1266 {
1267 signal_result (client,
1268 servicename,
1269 request_id,
1271 return;
1272 }
1273 sl->force_start = GNUNET_NO;
1274 if (GNUNET_YES == in_shutdown)
1275 {
1276 /* shutdown in progress */
1277 signal_result (client,
1278 servicename,
1279 request_id,
1281 return;
1282 }
1283 if (NULL != sl->killing_client)
1284 {
1285 /* killing already in progress */
1286 signal_result (client,
1287 servicename,
1288 request_id,
1290 return;
1291 }
1292 if (NULL == sl->proc)
1293 {
1294 /* process is down */
1295 signal_result (client,
1296 servicename,
1297 request_id,
1299 return;
1300 }
1302 "Sending kill signal to service `%s', waiting for process to die.\n",
1303 servicename);
1304 broadcast_status (servicename,
1306 NULL);
1307 /* no signal_start - only when it's STOPPED */
1309 if (GNUNET_OK !=
1313 "kill");
1314 sl->killing_client = client;
1315 sl->killing_client_request_id = request_id;
1316}

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_OK, GNUNET_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 1331 of file gnunet-service-arm.c.

1332{
1333 size_t next_pos = (*pool_pos) + strlen (str) + 1;
1334
1335 if (next_pos > pool_size)
1336 return GNUNET_SYSERR;
1337 memcpy (pool_start + *pool_pos, str, strlen (str) + 1);
1338 *pool_pos = next_pos;
1339 return GNUNET_OK;
1340}

References GNUNET_OK, GNUNET_SYSERR, and str.

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 1350 of file gnunet-service-arm.c.

1351{
1352 struct GNUNET_SERVICE_Client *client = cls;
1353 struct GNUNET_MQ_Envelope *env;
1355 size_t extra_size;
1356 struct ServiceList *sl;
1357 uint16_t count;
1358 size_t pool_size;
1359 size_t pool_pos;
1360 char *pool_start;
1362
1363 GNUNET_break_op (0 == ntohl (request->reserved));
1364 count = 0;
1365 pool_size = 0;
1366
1367 /* Do one pass over the list to compute the number of services
1368 * and the string pool size */
1369 for (sl = running_head; NULL != sl; sl = sl->next)
1370 {
1371 pool_size += strlen (sl->name) + 1;
1372 pool_size += strlen (sl->binary) + 1;
1373 count++;
1374 }
1375
1376 extra_size = pool_size + (count * sizeof (struct
1379 extra_size,
1381 msg->arm_msg.request_id = request->request_id;
1382 msg->count = htons (count);
1383
1384 ssm = (struct GNUNET_ARM_ServiceInfoMessage *) &msg[1];
1385 pool_start = (char *) (ssm + count);
1386 pool_pos = 0;
1387
1388 for (sl = running_head; NULL != sl; sl = sl->next)
1389 {
1390 ssm->name_index = htons ((uint16_t) pool_pos);
1391 GNUNET_assert (GNUNET_OK == pool_write (pool_start, pool_size, &pool_pos,
1392 sl->name));
1393 ssm->binary_index = htons ((uint16_t) pool_pos);
1394 GNUNET_assert (GNUNET_OK == pool_write (pool_start, pool_size, &pool_pos,
1395 sl->binary));
1396 if (NULL == sl->proc)
1397 {
1398 if (0 == sl->last_started_at.abs_value_us)
1399 {
1400 /* Process never started */
1402 }
1403 else if (0 == sl->last_exit_status)
1404 {
1406 }
1407 else
1408 {
1410 ssm->last_exit_status = htons (sl->last_exit_status);
1411 }
1412 }
1413 else if ((NULL != sl->killing_client) || (GNUNET_YES == in_shutdown))
1414 {
1416 }
1417 else
1418 {
1420 }
1423 ssm++;
1424 }
1427}

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 1437 of file gnunet-service-arm.c.

1438{
1439 struct GNUNET_SERVICE_Client *client = cls;
1440 struct GNUNET_MQ_Envelope *env;
1441 struct GNUNET_MessageHeader *msg;
1442
1443 (void) message;
1447}

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 1455 of file gnunet-service-arm.c.

1456{
1457 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Last shutdown phase\n");
1458 if (NULL != notifier)
1459 {
1461 notifier = NULL;
1462 }
1463 if (NULL != service)
1464 {
1466 service = NULL;
1467 }
1468 if (NULL != child_death_task)
1469 {
1471 child_death_task = NULL;
1472 }
1473}

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 1483 of file gnunet-service-arm.c.

1484{
1485 struct ServiceList *i;
1486 unsigned int res;
1487
1488 for (res = 0, i = run_head; NULL != i; i = i->next, res++)
1490 return res;
1491}

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 1500 of file gnunet-service-arm.c.

1501{
1502 struct ServiceList *pos;
1503 struct ServiceList *nxt;
1504 struct ServiceListeningInfo *sli;
1505
1506 (void) cls;
1507 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "First shutdown phase\n");
1508 if (NULL != child_restart_task)
1509 {
1511 child_restart_task = NULL;
1512 }
1514 /* first, stop listening */
1515 for (pos = running_head; NULL != pos; pos = pos->next)
1516 {
1517 while (NULL != (sli = pos->listen_head))
1518 {
1520 pos->listen_tail,
1521 sli);
1522 if (NULL != sli->accept_task)
1523 {
1525 sli->accept_task = NULL;
1526 }
1530 GNUNET_free (sli);
1531 }
1532 }
1533 /* then, shutdown all existing service processes */
1534 nxt = running_head;
1535 while (NULL != (pos = nxt))
1536 {
1537 nxt = pos->next;
1538 if (NULL != pos->proc)
1539 {
1541 "Stopping service `%s'\n",
1542 pos->name);
1544 if (GNUNET_OK !=
1548 "kill");
1549 }
1550 else
1551 {
1552 free_service (pos);
1553 }
1554 }
1555 /* finally, should all service processes be already gone, terminate for real */
1556 if (NULL == running_head)
1557 do_shutdown ();
1558 else
1560 "Delaying shutdown, have %u children still running\n",
1562}

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_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 1571 of file gnunet-service-arm.c.

1573{
1574 struct ServiceList *sl;
1575 struct GNUNET_TIME_Relative lowestRestartDelay;
1576 struct ServiceListeningInfo *sli;
1577
1578 (void) cls;
1579 child_restart_task = NULL;
1581 lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL;
1582
1583 /* check for services that need to be restarted due to
1584 * configuration changes or because the last restart failed */
1585 for (sl = running_head; NULL != sl; sl = sl->next)
1586 {
1587 if (NULL != sl->proc)
1588 continue;
1589 /* service is currently not running */
1591 {
1592 /* restart is now allowed */
1593 if (sl->force_start)
1594 {
1595 /* process should run by default, start immediately */
1597 _ ("Restarting service `%s'.\n"),
1598 sl->name);
1599 start_process (sl, NULL, 0);
1600 }
1601 else
1602 {
1603 /* process is run on-demand, ensure it is re-started if there is demand */
1604 for (sli = sl->listen_head; NULL != sli; sli = sli->next)
1605 if (NULL == sli->accept_task)
1606 {
1607 /* accept was actually paused, so start it again */
1608 sli->accept_task =
1610 sli->listen_socket,
1612 sli);
1613 }
1614 }
1615 }
1616 else
1617 {
1618 /* update calculation for earliest time to reactivate a service */
1619 lowestRestartDelay =
1620 GNUNET_TIME_relative_min (lowestRestartDelay,
1622 sl->restart_at));
1623 }
1624 }
1625 if (lowestRestartDelay.rel_value_us !=
1626 GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1627 {
1629 "Will restart process in %s\n",
1630 GNUNET_STRINGS_relative_time_to_string (lowestRestartDelay,
1631 GNUNET_YES));
1636 NULL);
1637 }
1638}

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 1648 of file gnunet-service-arm.c.

1649{
1650 struct ServiceList *pos;
1651 struct ServiceList *next;
1652 struct ServiceListeningInfo *sli;
1653 const char *statstr;
1654 int statcode;
1655 int ret;
1656 char c[16];
1657 enum GNUNET_OS_ProcessStatusType statusType;
1658 unsigned long statusCode;
1659 const struct GNUNET_DISK_FileHandle *pr;
1660
1661 (void) cls;
1664 child_death_task = NULL;
1665 /* consume the signal */
1666 GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof(c)));
1667
1668 /* check for services that died (WAITPID) */
1669 next = running_head;
1670 while (NULL != (pos = next))
1671 {
1672 next = pos->next;
1673
1674 if (NULL == pos->proc)
1675 {
1676 if (GNUNET_YES == in_shutdown)
1677 free_service (pos);
1678 continue;
1679 }
1680#if HAVE_WAIT4
1681 if (NULL != wait_file)
1682 {
1683 /* need to use 'wait4()' to obtain and log performance data */
1684 struct rusage ru;
1685 int status;
1686 pid_t pid;
1687
1689 ret = wait4 (pid,
1690 &status,
1691 WNOHANG,
1692 &ru);
1693 if (ret <= 0)
1694 continue; /* no process done */
1695 if (WIFEXITED (status))
1696 {
1697 statusType = GNUNET_OS_PROCESS_EXITED;
1698 statusCode = WEXITSTATUS (status);
1699 }
1700 else if (WIFSIGNALED (status))
1701 {
1702 statusType = GNUNET_OS_PROCESS_SIGNALED;
1703 statusCode = WTERMSIG (status);
1704 }
1705 else if (WIFSTOPPED (status))
1706 {
1707 statusType = GNUNET_OS_PROCESS_SIGNALED;
1708 statusCode = WSTOPSIG (status);
1709 }
1710#ifdef WIFCONTINUED
1711 else if (WIFCONTINUED (status))
1712 {
1713 statusType = GNUNET_OS_PROCESS_RUNNING;
1714 statusCode = 0;
1715 }
1716#endif
1717 else
1718 {
1719 statusType = GNUNET_OS_PROCESS_UNKNOWN;
1720 statusCode = 0;
1721 }
1722 if ((GNUNET_OS_PROCESS_EXITED == statusType) ||
1723 (GNUNET_OS_PROCESS_SIGNALED == statusType))
1724 {
1725 double utime = ru.ru_utime.tv_sec + (ru.ru_utime.tv_usec / 10e6);
1726 double stime = ru.ru_stime.tv_sec + (ru.ru_stime.tv_usec / 10e6);
1727 fprintf (wait_file,
1728 "%s(%u) %.3f %.3f %llu %llu %llu %llu %llu\n",
1729 pos->binary,
1730 (unsigned int) pid,
1731 utime,
1732 stime,
1733 (unsigned long long) ru.ru_maxrss,
1734 (unsigned long long) ru.ru_inblock,
1735 (unsigned long long) ru.ru_oublock,
1736 (unsigned long long) ru.ru_nvcsw,
1737 (unsigned long long) ru.ru_nivcsw);
1738 }
1739 }
1740 else /* continue with JUST this "if" as "else" (intentionally no brackets!) */
1741#endif
1742 if ((GNUNET_SYSERR ==
1743 (ret = GNUNET_process_wait (pos->proc,
1744 false,
1745 &statusType,
1746 &statusCode))) ||
1747 (ret == GNUNET_NO) ||
1748 (statusType == GNUNET_OS_PROCESS_STOPPED) ||
1749 (statusType == GNUNET_OS_PROCESS_UNKNOWN) ||
1750 (statusType == GNUNET_OS_PROCESS_RUNNING))
1751 continue;
1752
1753 if (statusType == GNUNET_OS_PROCESS_EXITED)
1754 {
1755 statstr = _ (/* process termination method */ "exit");
1756 statcode = statusCode;
1757 }
1758 else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
1759 {
1760 statstr = _ (/* process termination method */ "signal");
1761 statcode = statusCode;
1762 }
1763 else
1764 {
1765 statstr = _ (/* process termination method */ "unknown");
1766 statcode = 0;
1767 }
1768 if (0 != pos->killed_at.abs_value_us)
1769 {
1771 _ ("Service `%s' took %s to terminate\n"),
1772 pos->name,
1775 GNUNET_YES));
1776 }
1778 pos->proc = NULL;
1779 broadcast_status (pos->name,
1781 NULL);
1782 if (NULL != pos->killing_client)
1783 {
1785 pos->name,
1788 pos->killing_client = NULL;
1790 }
1791 if (GNUNET_YES != in_shutdown)
1792 {
1793 pos->last_exit_status = statcode;
1794 if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0))
1795 {
1796 /* process terminated normally, allow restart at any time */
1797 pos->restart_at.abs_value_us = 0;
1798 GNUNET_log (
1800 _ ("Service `%s' terminated normally, will restart at any time\n"),
1801 pos->name);
1802 /* process can still be re-started on-demand, ensure it is re-started if there is demand */
1803 for (sli = pos->listen_head; NULL != sli; sli = sli->next)
1804 {
1805 GNUNET_break (NULL == sli->accept_task);
1806 sli->accept_task =
1808 sli->listen_socket,
1810 sli);
1811 }
1812 }
1813 else
1814 {
1815 GNUNET_log (
1817 _ ("Service `%s' terminated with status %s/%d, will restart in %s\n"),
1818 pos->name,
1819 statstr,
1820 statcode,
1822 {
1823 /* Reduce backoff based on runtime of the process,
1824 so that there is a cool-down if a process actually
1825 runs for a while. */
1826 struct GNUNET_TIME_Relative runtime;
1827 unsigned int minutes;
1828
1830 minutes =
1831 runtime.rel_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us;
1832 if (minutes > 31)
1834 else
1835 pos->backoff.rel_value_us >>= minutes;
1836 }
1837 /* schedule restart */
1840 if (NULL != child_restart_task)
1845 NULL);
1846 }
1847 }
1848 else
1849 {
1850 free_service (pos);
1851 }
1852 }
1855 pr,
1857 NULL);
1858 if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
1859 do_shutdown ();
1860 else if (GNUNET_YES == in_shutdown)
1862 "Delaying shutdown after child's death, still have %u children\n",
1864}

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_EXITED, GNUNET_OS_PROCESS_RUNNING, GNUNET_OS_PROCESS_SIGNALED, GNUNET_OS_PROCESS_STOPPED, GNUNET_OS_PROCESS_UNKNOWN, GNUNET_process_destroy(), GNUNET_process_get_pid(), GNUNET_process_wait(), 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 1872 of file gnunet-service-arm.c.

1873{
1874 static char c;
1875 int old_errno = errno; /* back-up errno */
1876
1877 GNUNET_break (
1878 1 ==
1881 ,
1882 &c,
1883 sizeof(c)));
1884 errno = old_errno; /* restore errno */
1885}

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 1897 of file gnunet-service-arm.c.

1899{
1900 struct ServiceList *sl;
1901 char *binary;
1902 char *config;
1903 struct stat sbuf;
1904 struct sockaddr **addrs;
1905 socklen_t *addr_lens;
1906 int ret;
1907
1908 (void) cls;
1909 if (0 == strcasecmp (section, "arm"))
1910 return;
1911 if (GNUNET_OK !=
1913 section,
1914 "BINARY",
1915 &binary))
1916 {
1917 /* not a service section */
1918 return;
1919 }
1920 if (GNUNET_YES ==
1922 section,
1923 "RUN_PER_USER"))
1924 {
1925 if (GNUNET_NO == start_user)
1926 {
1927 GNUNET_free (binary);
1928 return; /* user service, and we don't deal with those */
1929 }
1930 }
1931 else
1932 {
1933 if (GNUNET_NO == start_system)
1934 {
1935 GNUNET_free (binary);
1936 return; /* system service, and we don't deal with those */
1937 }
1938 }
1939 sl = find_service (section);
1940 if (NULL != sl)
1941 {
1942 /* got the same section twice!? */
1943 GNUNET_break (0);
1944 GNUNET_free (binary);
1945 return;
1946 }
1947 config = NULL;
1948 if (((GNUNET_OK !=
1950 section,
1951 "CONFIG",
1952 &config)) &&
1953 (GNUNET_OK !=
1955 "PATHS",
1956 "DEFAULTCONFIG",
1957 &config))) ||
1958 (0 != stat (config,
1959 &sbuf)))
1960 {
1961 if (NULL != config)
1962 {
1964 section,
1965 "CONFIG",
1966 strerror (errno));
1968 config = NULL;
1969 }
1970 }
1971 sl = GNUNET_new (struct ServiceList);
1972 sl->name = GNUNET_strdup (section);
1973 sl->binary = binary;
1974 sl->config = config;
1977 sl->pipe_control =
1978 (GNUNET_YES ==
1980 section,
1981 "PIPECONTROL"));
1984 sl);
1985 if (GNUNET_YES ==
1987 section,
1988 "IMMEDIATE_START"))
1989 {
1990 sl->force_start = GNUNET_YES;
1991 if (GNUNET_YES ==
1993 section,
1994 "NOARMBIND"))
1995 return;
1996 }
1997 else
1998 {
1999 if (GNUNET_YES !=
2001 section,
2002 "START_ON_DEMAND"))
2003 return;
2004 }
2005 if (0 >= (ret = get_server_addresses (section,
2006 cfg,
2007 &addrs,
2008 &addr_lens)))
2009 return;
2010 /* this will free (or capture) addrs[i] */
2011 for (unsigned int i = 0; i < (unsigned int) ret; i++)
2012 create_listen_socket (addrs[i], addr_lens[i], sl);
2013 GNUNET_free (addrs);
2014 GNUNET_free (addr_lens);
2015}

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 2027 of file gnunet-service-arm.c.

2030{
2031 /* All clients are considered to be of the "monitor" kind
2032 * (that is, they don't affect ARM shutdown).
2033 */
2034 (void) cls;
2035 (void) mq;
2037 return client;
2038}

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 2049 of file gnunet-service-arm.c.

2052{
2053 (void) cls;
2054 GNUNET_assert (client == app_ctx);
2055 for (struct ServiceList *sl = running_head; NULL != sl; sl = sl->next)
2056 if (sl->killing_client == client)
2057 sl->killing_client = NULL;
2058}

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 2070 of file gnunet-service-arm.c.

2072{
2073 struct GNUNET_SERVICE_Client *client = cls;
2074
2075 (void) message;
2076 /* FIXME: might want to start by letting monitor know about
2077 services that are already running */
2078 /* Removal is handled by the server implementation, internally. */
2081 broadcast_status ("arm",
2083 client);
2085}

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 2096 of file gnunet-service-arm.c.

2099{
2100 struct ServiceList *sl;
2101 enum GNUNET_GenericReturnValue ret1;
2102 enum GNUNET_GenericReturnValue ret2;
2103
2104 (void) cls;
2105 cfg = c;
2106 service = serv;
2108 NULL);
2114 NULL);
2115#if HAVE_WAIT4
2116 if (GNUNET_OK ==
2118 "ARM",
2119 "RESOURCE_DIAGNOSTICS",
2120 &wait_filename))
2121 {
2122 wait_file = fopen (wait_filename, "w");
2123 if (NULL == wait_file)
2124 {
2126 "fopen",
2127 wait_filename);
2128 }
2129 }
2130#endif
2131 if (GNUNET_OK !=
2133 "ARM",
2134 "GLOBAL_PREFIX",
2137 else
2140 if (GNUNET_OK !=
2142 "ARM",
2143 "GLOBAL_POSTFIX",
2144 &final_option))
2146 else
2148 final_option);
2150 "ARM",
2151 "START_SYSTEM_SERVICES");
2153 "ARM",
2154 "START_USER_SERVICES");
2155 if ( (GNUNET_SYSERR == ret1) ||
2156 (GNUNET_SYSERR == ret2) )
2157 {
2158 /* invalid option */
2159 GNUNET_break (0);
2161 global_ret = 1;
2162 return;
2163 }
2165 "ARM",
2166 "START_SYSTEM_SERVICES"))
2167 ret1 = GNUNET_SYSERR;
2169 "ARM",
2170 "START_USER_SERVICES"))
2171 ret2 = GNUNET_SYSERR;
2172 start_system = (GNUNET_YES == ret1) ||
2173 ( (GNUNET_SYSERR == ret1) && (GNUNET_SYSERR == ret2) );
2174 start_user = (GNUNET_YES == ret2) ||
2175 ( (GNUNET_SYSERR == ret1) && (GNUNET_SYSERR == ret2) );
2176 if ( (GNUNET_NO == start_user) &&
2177 (GNUNET_NO == start_system) )
2178 {
2179 GNUNET_log (
2181 "Please enable either START_USER_SERVICES or START_SYSTEM_SERVICES\n");
2183 global_ret = 1;
2184 return;
2185 }
2188 NULL);
2189
2190 /* start default services... */
2191 for (sl = running_head; NULL != sl; sl = sl->next)
2192 if (GNUNET_YES == sl->force_start)
2193 start_process (sl, NULL, 0);
2195}

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 2206 of file gnunet-service-arm.c.

2207{
2212 struct GNUNET_ARM_Message,
2213 NULL),
2216 struct GNUNET_ARM_Message,
2217 NULL),
2220 struct GNUNET_MessageHeader,
2221 NULL),
2224 struct GNUNET_ARM_Message,
2225 NULL),
2228 struct GNUNET_MessageHeader,
2229 NULL),
2231 };
2232
2234 GNUNET_assert (NULL != sigpipe);
2235 shc_chld =
2238 if (0 !=
2240 argc,
2241 argv,
2242 "arm",
2245 &run,
2248 NULL,
2249 handlers))
2250 global_ret = 2;
2251#if HAVE_WAIT4
2252 if (NULL != wait_file)
2253 {
2254 fclose (wait_file);
2255 wait_file = NULL;
2256 }
2257 if (NULL != wait_filename)
2258 {
2259 GNUNET_free (wait_filename);
2260 wait_filename = NULL;
2261 }
2262#endif
2264 shc_chld = NULL;
2266 sigpipe = NULL;
2267 return global_ret;
2268}

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_peer_id_changed(), 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(), iterate_service_update_rooms(), open_service_room(), recv_message_miss(), remove_service_handle(), resolver_lookup_get_next_label(), run(), run(), run(), run(), run(), run(), run(), run(), run(), run(), 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().