GNUnet 0.26.2-44-g5a6b2f9a5
 
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);
759 sl->proc,
761 sl->pipe_control
765 for (struct ServiceListeningInfo *sli = sl->listen_head;
766 NULL != sli;
767 sli = sli->next)
768 {
771 sl->proc,
773 GNUNET_NETWORK_get_fd (sli->listen_socket))));
774 if (NULL != sli->accept_task)
775 {
776 GNUNET_SCHEDULER_cancel (sli->accept_task);
777 sli->accept_task = NULL;
778 }
779 }
780
781 /* obtain configuration */
782 if (GNUNET_OK !=
784 sl->name,
785 "PREFIX",
786 &loprefix))
787 loprefix = GNUNET_strdup (prefix_command);
788 else
790 loprefix);
791 if (GNUNET_OK !=
793 sl->name,
794 "OPTIONS",
795 &options))
796 options = NULL;
797 else
799 {
800 char *new_options;
801 char *optpos;
802 char *fin_options;
803
804 fin_options = GNUNET_strdup (final_option);
805 /* replace '{}' with service name */
806 while (NULL != (optpos = strstr (fin_options, "{}")))
807 {
808 /* terminate string at opening parenthesis */
809 *optpos = 0;
810 GNUNET_asprintf (&new_options,
811 "%s%s%s",
812 fin_options,
813 sl->name,
814 optpos + 2);
815 GNUNET_free (fin_options);
816 fin_options = new_options;
817 }
818 if (NULL != options)
819 {
820 /* combine "fin_options" with "options" */
821 optpos = options;
823 "%s %s",
824 fin_options,
825 optpos);
826 GNUNET_free (fin_options);
827 GNUNET_free (optpos);
828 }
829 else
830 {
831 /* only have "fin_options", use that */
832 options = fin_options;
833 }
834 }
836 options);
838 sl->name,
839 "DEBUG");
840 {
841 const char *service_type = NULL;
842 const char *choices[] = {
843 "GNUNET",
844 "SIMPLE",
845 NULL
846 };
847
848 is_simple_service = false;
849 if ( (GNUNET_OK ==
851 sl->name,
852 "TYPE",
853 choices,
854 &service_type)) &&
855 (0 == strcasecmp (service_type,
856 "SIMPLE")) )
857 is_simple_service = true;
858 }
859
860 if (is_simple_service)
861 {
862 /* A simple service will receive no GNUnet specific
863 command line options. */
864 binary = GNUNET_strdup (sl->binary);
866 binary);
868 "Starting simple service `%s' using binary `%s'\n",
869 sl->name,
870 sl->binary);
872 loprefix,
873 binary,
874 options,
875 NULL);
876 }
877 else
878 {
879 char *command;
880
881 /* actually start process */
883 "Starting service `%s' using binary `%s' and configuration `%s'\n",
884 sl->name,
885 sl->binary,
886 sl->config);
889 sl->binary);
890 GNUNET_asprintf (&command,
891 "%s%s%s%s%s%s%s%s",
892 loprefix,
893 (0 == strlen (loprefix)) ? "" : " ",
894 binary,
895 (use_debug) ? " -L DEBUG" : "",
896 (NULL == sl->config) ? "" : " -c ",
897 (NULL == sl->config) ? "" : sl->config,
898 (0 == strlen (options)) ? "" : " ",
899 options);
901 "Launching GNUnet service `%s'\n",
902 command);
904 sl->proc,
905 command);
906 GNUNET_free (command);
907 }
908
909 if ( (GNUNET_OK != ret) ||
910 (GNUNET_OK !=
911 GNUNET_process_start (sl->proc) ) )
912 {
913 GNUNET_break (0);
914 goto failure;
915 }
916
919 "Starting service `%s'\n",
920 sl->name);
923 NULL);
924 if (client)
925 signal_result (client,
926 sl->name,
927 request_id,
929 goto cleanup;
930failure:
931 if (NULL != sl->proc)
932 {
934 sl->proc = NULL;
935 }
937 "Failed to start service `%s'\n",
938 sl->name);
939 if (client)
940 signal_result (client,
941 sl->name,
942 request_id,
944cleanup:
945 GNUNET_free (binary);
946 GNUNET_free (loprefix);
948}
949
950
958static struct ServiceList *
959find_service (const char *name)
960{
961 struct ServiceList *sl;
962
963 sl = running_head;
964 while (sl != NULL)
965 {
966 if (0 == strcasecmp (sl->name, name))
967 return sl;
968 sl = sl->next;
969 }
970 return NULL;
971}
972
973
980static void
981accept_connection (void *cls)
982{
983 struct ServiceListeningInfo *sli = cls;
984 struct ServiceList *sl = sli->sl;
985
986 sli->accept_task = NULL;
988 start_process (sl, NULL, 0);
989}
990
991
1000static void
1001create_listen_socket (struct sockaddr *sa,
1002 socklen_t addr_len,
1003 struct ServiceList *sl)
1004{
1005 static int on = 1;
1006 struct GNUNET_NETWORK_Handle *sock;
1007 struct ServiceListeningInfo *sli;
1008
1009 int match_uid;
1010 int match_gid;
1011
1012 switch (sa->sa_family)
1013 {
1014 case AF_INET:
1015 sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
1016 break;
1017
1018 case AF_INET6:
1019 sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1020 break;
1021
1022 case AF_UNIX:
1023 if (0 == strcmp (GNUNET_a2s (sa, addr_len),
1024 "@")) /* Do not bind to blank UNIX path! */
1025 return;
1026 sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
1027 break;
1028
1029 default:
1030 GNUNET_break (0);
1031 sock = NULL;
1032 errno = EAFNOSUPPORT;
1033 break;
1034 }
1035 if (NULL == sock)
1036 {
1038 _ ("Unable to create socket for service `%s': %s\n"),
1039 sl->name,
1040 strerror (errno));
1041 GNUNET_free (sa);
1042 return;
1043 }
1045 SOL_SOCKET,
1046 SO_REUSEADDR,
1047 &on,
1048 sizeof(on)))
1050 "setsockopt");
1051#ifdef IPV6_V6ONLY
1052 if ((sa->sa_family == AF_INET6) &&
1054 IPPROTO_IPV6,
1055 IPV6_V6ONLY,
1056 &on,
1057 sizeof(on))))
1059 "setsockopt");
1060#endif
1061 if (AF_UNIX == sa->sa_family)
1062 GNUNET_NETWORK_unix_precheck ((struct sockaddr_un *) sa);
1063 if (GNUNET_OK !=
1064 GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) sa, addr_len))
1065 {
1066 GNUNET_log (
1068 _ (
1069 "Unable to bind listening socket for service `%s' to address `%s': %s\n"),
1070 sl->name,
1071 GNUNET_a2s (sa, addr_len),
1072 strerror (errno));
1074 GNUNET_free (sa);
1075 return;
1076 }
1077 if ((AF_UNIX == sa->sa_family)
1078#ifdef __linux__
1079 /* Permission settings are not required when abstract sockets are used */
1080 && ('\0' != ((const struct sockaddr_un *) sa)->sun_path[0])
1081#endif
1082 )
1083 {
1084 match_uid =
1085 (GNUNET_YES ==
1087 sl->name,
1088 "UNIX_MATCH_UID"));
1089 match_gid =
1090 (GNUNET_YES ==
1092 sl->name,
1093 "UNIX_MATCH_GID"));
1094 GNUNET_DISK_fix_permissions (((const struct sockaddr_un *) sa)->sun_path,
1095 match_uid,
1096 match_gid);
1097 }
1098 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
1099 {
1102 GNUNET_free (sa);
1103 return;
1104 }
1106 _ ("ARM now monitors connections to service `%s' at `%s'\n"),
1107 sl->name,
1108 GNUNET_a2s (sa, addr_len));
1109 sli = GNUNET_new (struct ServiceListeningInfo);
1110 sli->service_addr = sa;
1111 sli->service_addr_len = addr_len;
1112 sli->listen_socket = sock;
1113 sli->sl = sl;
1114 sli->accept_task =
1116 sock,
1118 sli);
1120}
1121
1122
1129static void
1130free_service (struct ServiceList *sl)
1131{
1134 GNUNET_assert (NULL == sl->listen_head);
1137 GNUNET_free (sl->name);
1138 GNUNET_free (sl);
1139}
1140
1141
1150static int
1151check_start (void *cls, const struct GNUNET_ARM_Message *amsg)
1152{
1153 (void) cls;
1155 return GNUNET_OK;
1156}
1157
1158
1165static void
1166handle_start (void *cls, const struct GNUNET_ARM_Message *amsg)
1167{
1168 struct GNUNET_SERVICE_Client *client = cls;
1169 const char *servicename;
1170 struct ServiceList *sl;
1171 uint64_t request_id;
1172
1173 request_id = GNUNET_ntohll (amsg->request_id);
1174 servicename = (const char *) &amsg[1];
1176 if (GNUNET_YES == in_shutdown)
1177 {
1178 signal_result (client,
1179 servicename,
1180 request_id,
1182 return;
1183 }
1184 sl = find_service (servicename);
1185 if (NULL == sl)
1186 {
1187 signal_result (client,
1188 servicename,
1189 request_id,
1191 return;
1192 }
1193 sl->force_start = GNUNET_YES;
1194 if (NULL != sl->proc)
1195 {
1196 signal_result (client,
1197 servicename,
1198 request_id,
1200 return;
1201 }
1202 start_process (sl, client, request_id);
1203}
1204
1205
1211static void
1212trigger_shutdown (void *cls)
1213{
1214 (void) cls;
1215 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Triggering shutdown\n");
1217}
1218
1219
1228static int
1229check_stop (void *cls,
1230 const struct GNUNET_ARM_Message *amsg)
1231{
1232 (void) cls;
1234 return GNUNET_OK;
1235}
1236
1237
1244static void
1245handle_stop (void *cls,
1246 const struct GNUNET_ARM_Message *amsg)
1247{
1248 struct GNUNET_SERVICE_Client *client = cls;
1249 struct ServiceList *sl;
1250 const char *servicename;
1251 uint64_t request_id;
1252
1253 request_id = GNUNET_ntohll (amsg->request_id);
1254 servicename = (const char *) &amsg[1];
1256 _ ("Preparing to stop `%s'\n"),
1257 servicename);
1259 if (0 == strcasecmp (servicename, "arm"))
1260 {
1261 broadcast_status (servicename, GNUNET_ARM_SERVICE_STOPPING, NULL);
1262 signal_result (client,
1263 servicename,
1264 request_id,
1268 return;
1269 }
1270 sl = find_service (servicename);
1271 if (NULL == sl)
1272 {
1273 signal_result (client,
1274 servicename,
1275 request_id,
1277 return;
1278 }
1279 sl->force_start = GNUNET_NO;
1280 if (GNUNET_YES == in_shutdown)
1281 {
1282 /* shutdown in progress */
1283 signal_result (client,
1284 servicename,
1285 request_id,
1287 return;
1288 }
1289 if (NULL != sl->killing_client)
1290 {
1291 /* killing already in progress */
1292 signal_result (client,
1293 servicename,
1294 request_id,
1296 return;
1297 }
1298 if (NULL == sl->proc)
1299 {
1300 /* process is down */
1301 signal_result (client,
1302 servicename,
1303 request_id,
1305 return;
1306 }
1308 "Sending kill signal to service `%s', waiting for process to die.\n",
1309 servicename);
1310 broadcast_status (servicename,
1312 NULL);
1313 /* no signal_start - only when it's STOPPED */
1315 if (GNUNET_OK !=
1319 "kill");
1320 sl->killing_client = client;
1321 sl->killing_client_request_id = request_id;
1322}
1323
1324
1336static int
1337pool_write (char *pool_start, size_t pool_size, size_t *pool_pos, char *str)
1338{
1339 size_t next_pos = (*pool_pos) + strlen (str) + 1;
1340
1341 if (next_pos > pool_size)
1342 return GNUNET_SYSERR;
1343 memcpy (pool_start + *pool_pos, str, strlen (str) + 1);
1344 *pool_pos = next_pos;
1345 return GNUNET_OK;
1346}
1347
1348
1355static void
1356handle_list (void *cls, const struct GNUNET_ARM_Message *request)
1357{
1358 struct GNUNET_SERVICE_Client *client = cls;
1359 struct GNUNET_MQ_Envelope *env;
1361 size_t extra_size;
1362 struct ServiceList *sl;
1363 uint16_t count;
1364 size_t pool_size;
1365 size_t pool_pos;
1366 char *pool_start;
1368
1369 GNUNET_break_op (0 == ntohl (request->reserved));
1370 count = 0;
1371 pool_size = 0;
1372
1373 /* Do one pass over the list to compute the number of services
1374 * and the string pool size */
1375 for (sl = running_head; NULL != sl; sl = sl->next)
1376 {
1377 pool_size += strlen (sl->name) + 1;
1378 pool_size += strlen (sl->binary) + 1;
1379 count++;
1380 }
1381
1382 extra_size = pool_size + (count * sizeof (struct
1385 extra_size,
1387 msg->arm_msg.request_id = request->request_id;
1388 msg->count = htons (count);
1389
1390 ssm = (struct GNUNET_ARM_ServiceInfoMessage *) &msg[1];
1391 pool_start = (char *) (ssm + count);
1392 pool_pos = 0;
1393
1394 for (sl = running_head; NULL != sl; sl = sl->next)
1395 {
1396 ssm->name_index = htons ((uint16_t) pool_pos);
1397 GNUNET_assert (GNUNET_OK == pool_write (pool_start, pool_size, &pool_pos,
1398 sl->name));
1399 ssm->binary_index = htons ((uint16_t) pool_pos);
1400 GNUNET_assert (GNUNET_OK == pool_write (pool_start, pool_size, &pool_pos,
1401 sl->binary));
1402 if (NULL == sl->proc)
1403 {
1404 if (0 == sl->last_started_at.abs_value_us)
1405 {
1406 /* Process never started */
1408 }
1409 else if (0 == sl->last_exit_status)
1410 {
1412 }
1413 else
1414 {
1416 ssm->last_exit_status = htons (sl->last_exit_status);
1417 }
1418 }
1419 else if ((NULL != sl->killing_client) || (GNUNET_YES == in_shutdown))
1420 {
1422 }
1423 else
1424 {
1426 }
1429 ssm++;
1430 }
1433}
1434
1435
1442static void
1443handle_test (void *cls, const struct GNUNET_MessageHeader *message)
1444{
1445 struct GNUNET_SERVICE_Client *client = cls;
1446 struct GNUNET_MQ_Envelope *env;
1447 struct GNUNET_MessageHeader *msg;
1448
1449 (void) message;
1453}
1454
1455
1460static void
1461do_shutdown ()
1462{
1463 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Last shutdown phase\n");
1464 if (NULL != notifier)
1465 {
1467 notifier = NULL;
1468 }
1469 if (NULL != service)
1470 {
1472 service = NULL;
1473 }
1474 if (NULL != child_death_task)
1475 {
1477 child_death_task = NULL;
1478 }
1479}
1480
1481
1488static unsigned int
1489list_count (struct ServiceList *run_head)
1490{
1491 struct ServiceList *i;
1492 unsigned int res;
1493
1494 for (res = 0, i = run_head; NULL != i; i = i->next, res++)
1496 return res;
1497}
1498
1499
1505static void
1506shutdown_task (void *cls)
1507{
1508 struct ServiceList *pos;
1509 struct ServiceList *nxt;
1510 struct ServiceListeningInfo *sli;
1511
1512 (void) cls;
1513 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "First shutdown phase\n");
1514 if (NULL != child_restart_task)
1515 {
1517 child_restart_task = NULL;
1518 }
1520 /* first, stop listening */
1521 for (pos = running_head; NULL != pos; pos = pos->next)
1522 {
1523 while (NULL != (sli = pos->listen_head))
1524 {
1526 pos->listen_tail,
1527 sli);
1528 if (NULL != sli->accept_task)
1529 {
1531 sli->accept_task = NULL;
1532 }
1536 GNUNET_free (sli);
1537 }
1538 }
1539 /* then, shutdown all existing service processes */
1540 nxt = running_head;
1541 while (NULL != (pos = nxt))
1542 {
1543 nxt = pos->next;
1544 if (NULL != pos->proc)
1545 {
1547 "Stopping service `%s'\n",
1548 pos->name);
1550 if (GNUNET_OK !=
1554 "kill");
1555 }
1556 else
1557 {
1558 free_service (pos);
1559 }
1560 }
1561 /* finally, should all service processes be already gone, terminate for real */
1562 if (NULL == running_head)
1563 do_shutdown ();
1564 else
1566 "Delaying shutdown, have %u children still running\n",
1568}
1569
1570
1576static void
1577delayed_restart_task (void *cls)
1578
1579{
1580 struct ServiceList *sl;
1581 struct GNUNET_TIME_Relative lowestRestartDelay;
1582 struct ServiceListeningInfo *sli;
1583
1584 (void) cls;
1585 child_restart_task = NULL;
1587 lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL;
1588
1589 /* check for services that need to be restarted due to
1590 * configuration changes or because the last restart failed */
1591 for (sl = running_head; NULL != sl; sl = sl->next)
1592 {
1593 if (NULL != sl->proc)
1594 continue;
1595 /* service is currently not running */
1597 {
1598 /* restart is now allowed */
1599 if (sl->force_start)
1600 {
1601 /* process should run by default, start immediately */
1603 _ ("Restarting service `%s'.\n"),
1604 sl->name);
1605 start_process (sl, NULL, 0);
1606 }
1607 else
1608 {
1609 /* process is run on-demand, ensure it is re-started if there is demand */
1610 for (sli = sl->listen_head; NULL != sli; sli = sli->next)
1611 if (NULL == sli->accept_task)
1612 {
1613 /* accept was actually paused, so start it again */
1614 sli->accept_task =
1616 sli->listen_socket,
1618 sli);
1619 }
1620 }
1621 }
1622 else
1623 {
1624 /* update calculation for earliest time to reactivate a service */
1625 lowestRestartDelay =
1626 GNUNET_TIME_relative_min (lowestRestartDelay,
1628 sl->restart_at));
1629 }
1630 }
1631 if (lowestRestartDelay.rel_value_us !=
1632 GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1633 {
1635 "Will restart process in %s\n",
1636 GNUNET_STRINGS_relative_time_to_string (lowestRestartDelay,
1637 GNUNET_YES));
1642 NULL);
1643 }
1644}
1645
1646
1653static void
1654maint_child_death (void *cls)
1655{
1656 struct ServiceList *pos;
1657 struct ServiceList *next;
1658 struct ServiceListeningInfo *sli;
1659 const char *statstr;
1660 int statcode;
1661 int ret;
1662 char c[16];
1663 enum GNUNET_OS_ProcessStatusType statusType;
1664 unsigned long statusCode;
1665 const struct GNUNET_DISK_FileHandle *pr;
1666
1667 (void) cls;
1670 child_death_task = NULL;
1671 /* consume the signal */
1672 GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof(c)));
1673
1674 /* check for services that died (WAITPID) */
1675 next = running_head;
1676 while (NULL != (pos = next))
1677 {
1678 next = pos->next;
1679
1680 if (NULL == pos->proc)
1681 {
1682 if (GNUNET_YES == in_shutdown)
1683 free_service (pos);
1684 continue;
1685 }
1686#if HAVE_WAIT4
1687 if (NULL != wait_file)
1688 {
1689 /* need to use 'wait4()' to obtain and log performance data */
1690 struct rusage ru;
1691 int status;
1692 pid_t pid;
1693
1695 ret = wait4 (pid,
1696 &status,
1697 WNOHANG,
1698 &ru);
1699 if (ret <= 0)
1700 continue; /* no process done */
1701 if (WIFEXITED (status))
1702 {
1703 statusType = GNUNET_OS_PROCESS_EXITED;
1704 statusCode = WEXITSTATUS (status);
1705 }
1706 else if (WIFSIGNALED (status))
1707 {
1708 statusType = GNUNET_OS_PROCESS_SIGNALED;
1709 statusCode = WTERMSIG (status);
1710 }
1711 else if (WIFSTOPPED (status))
1712 {
1713 statusType = GNUNET_OS_PROCESS_SIGNALED;
1714 statusCode = WSTOPSIG (status);
1715 }
1716#ifdef WIFCONTINUED
1717 else if (WIFCONTINUED (status))
1718 {
1719 statusType = GNUNET_OS_PROCESS_RUNNING;
1720 statusCode = 0;
1721 }
1722#endif
1723 else
1724 {
1725 statusType = GNUNET_OS_PROCESS_UNKNOWN;
1726 statusCode = 0;
1727 }
1728 if ((GNUNET_OS_PROCESS_EXITED == statusType) ||
1729 (GNUNET_OS_PROCESS_SIGNALED == statusType))
1730 {
1731 double utime = ru.ru_utime.tv_sec + (ru.ru_utime.tv_usec / 10e6);
1732 double stime = ru.ru_stime.tv_sec + (ru.ru_stime.tv_usec / 10e6);
1733 fprintf (wait_file,
1734 "%s(%u) %.3f %.3f %llu %llu %llu %llu %llu\n",
1735 pos->binary,
1736 (unsigned int) pid,
1737 utime,
1738 stime,
1739 (unsigned long long) ru.ru_maxrss,
1740 (unsigned long long) ru.ru_inblock,
1741 (unsigned long long) ru.ru_oublock,
1742 (unsigned long long) ru.ru_nvcsw,
1743 (unsigned long long) ru.ru_nivcsw);
1744 }
1745 }
1746 else /* continue with JUST this "if" as "else" (intentionally no brackets!) */
1747#endif
1748 if ((GNUNET_SYSERR ==
1749 (ret = GNUNET_process_wait (pos->proc,
1750 false,
1751 &statusType,
1752 &statusCode))) ||
1753 (ret == GNUNET_NO) ||
1754 (statusType == GNUNET_OS_PROCESS_STOPPED) ||
1755 (statusType == GNUNET_OS_PROCESS_UNKNOWN) ||
1756 (statusType == GNUNET_OS_PROCESS_RUNNING))
1757 continue;
1758
1759 if (statusType == GNUNET_OS_PROCESS_EXITED)
1760 {
1761 statstr = _ (/* process termination method */ "exit");
1762 statcode = statusCode;
1763 }
1764 else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
1765 {
1766 statstr = _ (/* process termination method */ "signal");
1767 statcode = statusCode;
1768 }
1769 else
1770 {
1771 statstr = _ (/* process termination method */ "unknown");
1772 statcode = 0;
1773 }
1774 if (0 != pos->killed_at.abs_value_us)
1775 {
1777 _ ("Service `%s' took %s to terminate\n"),
1778 pos->name,
1781 GNUNET_YES));
1782 }
1784 pos->proc = NULL;
1785 broadcast_status (pos->name,
1787 NULL);
1788 if (NULL != pos->killing_client)
1789 {
1791 pos->name,
1794 pos->killing_client = NULL;
1796 }
1797 if (GNUNET_YES != in_shutdown)
1798 {
1799 pos->last_exit_status = statcode;
1800 if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0))
1801 {
1802 /* process terminated normally, allow restart at any time */
1803 pos->restart_at.abs_value_us = 0;
1804 GNUNET_log (
1806 _ ("Service `%s' terminated normally, will restart at any time\n"),
1807 pos->name);
1808 /* process can still be re-started on-demand, ensure it is re-started if there is demand */
1809 for (sli = pos->listen_head; NULL != sli; sli = sli->next)
1810 {
1811 GNUNET_break (NULL == sli->accept_task);
1812 sli->accept_task =
1814 sli->listen_socket,
1816 sli);
1817 }
1818 }
1819 else
1820 {
1821 GNUNET_log (
1823 _ ("Service `%s' terminated with status %s/%d, will restart in %s\n"),
1824 pos->name,
1825 statstr,
1826 statcode,
1828 {
1829 /* Reduce backoff based on runtime of the process,
1830 so that there is a cool-down if a process actually
1831 runs for a while. */
1832 struct GNUNET_TIME_Relative runtime;
1833 unsigned int minutes;
1834
1836 minutes =
1837 runtime.rel_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us;
1838 if (minutes > 31)
1840 else
1841 pos->backoff.rel_value_us >>= minutes;
1842 }
1843 /* schedule restart */
1846 if (NULL != child_restart_task)
1851 NULL);
1852 }
1853 }
1854 else
1855 {
1856 free_service (pos);
1857 }
1858 }
1861 pr,
1863 NULL);
1864 if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
1865 do_shutdown ();
1866 else if (GNUNET_YES == in_shutdown)
1868 "Delaying shutdown after child's death, still have %u children\n",
1870}
1871
1872
1877static void
1879{
1880 static char c;
1881 int old_errno = errno; /* back-up errno */
1882
1883 GNUNET_break (
1884 1 ==
1887 ,
1888 &c,
1889 sizeof(c)));
1890 errno = old_errno; /* restore errno */
1891}
1892
1893
1902static void
1903setup_service (void *cls,
1904 const char *section)
1905{
1906 struct ServiceList *sl;
1907 char *binary;
1908 char *config;
1909 struct stat sbuf;
1910 struct sockaddr **addrs;
1911 socklen_t *addr_lens;
1912 int ret;
1913
1914 (void) cls;
1915 if (0 == strcasecmp (section, "arm"))
1916 return;
1917 if (GNUNET_OK !=
1919 section,
1920 "BINARY",
1921 &binary))
1922 {
1923 /* not a service section */
1924 return;
1925 }
1926 if (GNUNET_YES ==
1928 section,
1929 "RUN_PER_USER"))
1930 {
1931 if (GNUNET_NO == start_user)
1932 {
1933 GNUNET_free (binary);
1934 return; /* user service, and we don't deal with those */
1935 }
1936 }
1937 else
1938 {
1939 if (GNUNET_NO == start_system)
1940 {
1941 GNUNET_free (binary);
1942 return; /* system service, and we don't deal with those */
1943 }
1944 }
1945 sl = find_service (section);
1946 if (NULL != sl)
1947 {
1948 /* got the same section twice!? */
1949 GNUNET_break (0);
1950 GNUNET_free (binary);
1951 return;
1952 }
1953 config = NULL;
1954 if (((GNUNET_OK !=
1956 section,
1957 "CONFIG",
1958 &config)) &&
1959 (GNUNET_OK !=
1961 "PATHS",
1962 "DEFAULTCONFIG",
1963 &config))) ||
1964 (0 != stat (config,
1965 &sbuf)))
1966 {
1967 if (NULL != config)
1968 {
1970 section,
1971 "CONFIG",
1972 strerror (errno));
1974 config = NULL;
1975 }
1976 }
1977 sl = GNUNET_new (struct ServiceList);
1978 sl->name = GNUNET_strdup (section);
1979 sl->binary = binary;
1980 sl->config = config;
1983 sl->pipe_control =
1984 (GNUNET_YES ==
1986 section,
1987 "PIPECONTROL"));
1990 sl);
1991 if (GNUNET_YES ==
1993 section,
1994 "IMMEDIATE_START"))
1995 {
1996 sl->force_start = GNUNET_YES;
1997 if (GNUNET_YES ==
1999 section,
2000 "NOARMBIND"))
2001 return;
2002 }
2003 else
2004 {
2005 if (GNUNET_YES !=
2007 section,
2008 "START_ON_DEMAND"))
2009 return;
2010 }
2011 if (0 >= (ret = get_server_addresses (section,
2012 cfg,
2013 &addrs,
2014 &addr_lens)))
2015 return;
2016 /* this will free (or capture) addrs[i] */
2017 for (unsigned int i = 0; i < (unsigned int) ret; i++)
2018 create_listen_socket (addrs[i], addr_lens[i], sl);
2019 GNUNET_free (addrs);
2020 GNUNET_free (addr_lens);
2021}
2022
2023
2032static void *
2033client_connect_cb (void *cls,
2034 struct GNUNET_SERVICE_Client *client,
2035 struct GNUNET_MQ_Handle *mq)
2036{
2037 /* All clients are considered to be of the "monitor" kind
2038 * (that is, they don't affect ARM shutdown).
2039 */
2040 (void) cls;
2041 (void) mq;
2043 return client;
2044}
2045
2046
2054static void
2055client_disconnect_cb (void *cls,
2056 struct GNUNET_SERVICE_Client *client,
2057 void *app_ctx)
2058{
2059 (void) cls;
2060 GNUNET_assert (client == app_ctx);
2061 for (struct ServiceList *sl = running_head; NULL != sl; sl = sl->next)
2062 if (sl->killing_client == client)
2063 sl->killing_client = NULL;
2064}
2065
2066
2075static void
2076handle_monitor (void *cls,
2077 const struct GNUNET_MessageHeader *message)
2078{
2079 struct GNUNET_SERVICE_Client *client = cls;
2080
2081 (void) message;
2082 /* FIXME: might want to start by letting monitor know about
2083 services that are already running */
2084 /* Removal is handled by the server implementation, internally. */
2087 broadcast_status ("arm",
2089 client);
2091}
2092
2093
2101static void
2102run (void *cls,
2103 const struct GNUNET_CONFIGURATION_Handle *c,
2104 struct GNUNET_SERVICE_Handle *serv)
2105{
2106 struct ServiceList *sl;
2107 enum GNUNET_GenericReturnValue ret1;
2108 enum GNUNET_GenericReturnValue ret2;
2109
2110 (void) cls;
2111 cfg = c;
2112 service = serv;
2114 NULL);
2120 NULL);
2121#if HAVE_WAIT4
2122 if (GNUNET_OK ==
2124 "ARM",
2125 "RESOURCE_DIAGNOSTICS",
2126 &wait_filename))
2127 {
2128 wait_file = fopen (wait_filename, "w");
2129 if (NULL == wait_file)
2130 {
2132 "fopen",
2133 wait_filename);
2134 }
2135 }
2136#endif
2137 if (GNUNET_OK !=
2139 "ARM",
2140 "GLOBAL_PREFIX",
2143 else
2146 if (GNUNET_OK !=
2148 "ARM",
2149 "GLOBAL_POSTFIX",
2150 &final_option))
2152 else
2154 final_option);
2156 "ARM",
2157 "START_SYSTEM_SERVICES");
2159 "ARM",
2160 "START_USER_SERVICES");
2161 if ( (GNUNET_SYSERR == ret1) ||
2162 (GNUNET_SYSERR == ret2) )
2163 {
2164 /* invalid option */
2165 GNUNET_break (0);
2167 global_ret = 1;
2168 return;
2169 }
2171 "ARM",
2172 "START_SYSTEM_SERVICES"))
2173 ret1 = GNUNET_SYSERR;
2175 "ARM",
2176 "START_USER_SERVICES"))
2177 ret2 = GNUNET_SYSERR;
2178 start_system = (GNUNET_YES == ret1) ||
2179 ( (GNUNET_SYSERR == ret1) && (GNUNET_SYSERR == ret2) );
2180 start_user = (GNUNET_YES == ret2) ||
2181 ( (GNUNET_SYSERR == ret1) && (GNUNET_SYSERR == ret2) );
2182 if ( (GNUNET_NO == start_user) &&
2183 (GNUNET_NO == start_system) )
2184 {
2185 GNUNET_log (
2187 "Please enable either START_USER_SERVICES or START_SYSTEM_SERVICES\n");
2189 global_ret = 1;
2190 return;
2191 }
2194 NULL);
2195
2196 /* start default services... */
2197 for (sl = running_head; NULL != sl; sl = sl->next)
2198 if (GNUNET_YES == sl->force_start)
2199 start_process (sl, NULL, 0);
2201}
2202
2203
2211int
2212main (int argc, char *const *argv)
2213{
2218 struct GNUNET_ARM_Message,
2219 NULL),
2222 struct GNUNET_ARM_Message,
2223 NULL),
2226 struct GNUNET_MessageHeader,
2227 NULL),
2230 struct GNUNET_ARM_Message,
2231 NULL),
2234 struct GNUNET_MessageHeader,
2235 NULL),
2237 };
2238
2240 GNUNET_assert (NULL != sigpipe);
2241 shc_chld =
2244 if (0 !=
2246 argc,
2247 argv,
2248 "arm",
2251 &run,
2254 NULL,
2255 handlers))
2256 global_ret = 2;
2257#if HAVE_WAIT4
2258 if (NULL != wait_file)
2259 {
2260 fclose (wait_file);
2261 wait_file = NULL;
2262 }
2263 if (NULL != wait_filename)
2264 {
2265 GNUNET_free (wait_filename);
2266 wait_filename = NULL;
2267 }
2268#endif
2270 shc_chld = NULL;
2272 sigpipe = NULL;
2273 return global_ret;
2274}
2275
2276
2277#if defined(__linux__) && defined(__GLIBC__)
2278#include <malloc.h>
2279
2280void __attribute__ ((constructor))
2281GNUNET_ARM_memory_init (void);
2282
2286void __attribute__ ((constructor))
2287GNUNET_ARM_memory_init (void)
2288{
2289 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2290 mallopt (M_TOP_PAD, 1 * 1024);
2291 malloc_trim (0);
2292}
2293
2294
2295#endif
2296
2297
2298/* 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.
struct GNUNET_Process * GNUNET_process_create(void)
Create a process handle.
Definition os_process.c:462
enum GNUNET_GenericReturnValue GNUNET_process_set_command(struct GNUNET_Process *p, const char *command)
Set the command to start a process.
Definition os_process.c:921
#define GNUNET_process_option_inherit_lsock(lsock)
Pass listen socket to child systemd-style.
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_option_std_inheritance(flags)
Set flags about standard inheritance options.
enum GNUNET_GenericReturnValue GNUNET_process_start(struct GNUNET_Process *proc)
Start a process.
Definition os_process.c:545
enum GNUNET_GenericReturnValue GNUNET_process_set_command_va(struct GNUNET_Process *p, const char *filename,...)
Set the command to start a process.
Definition os_process.c:903
#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
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);
760 sl->proc,
762 sl->pipe_control
766 for (struct ServiceListeningInfo *sli = sl->listen_head;
767 NULL != sli;
768 sli = sli->next)
769 {
772 sl->proc,
774 GNUNET_NETWORK_get_fd (sli->listen_socket))));
775 if (NULL != sli->accept_task)
776 {
777 GNUNET_SCHEDULER_cancel (sli->accept_task);
778 sli->accept_task = NULL;
779 }
780 }
781
782 /* obtain configuration */
783 if (GNUNET_OK !=
785 sl->name,
786 "PREFIX",
787 &loprefix))
788 loprefix = GNUNET_strdup (prefix_command);
789 else
791 loprefix);
792 if (GNUNET_OK !=
794 sl->name,
795 "OPTIONS",
796 &options))
797 options = NULL;
798 else
800 {
801 char *new_options;
802 char *optpos;
803 char *fin_options;
804
805 fin_options = GNUNET_strdup (final_option);
806 /* replace '{}' with service name */
807 while (NULL != (optpos = strstr (fin_options, "{}")))
808 {
809 /* terminate string at opening parenthesis */
810 *optpos = 0;
811 GNUNET_asprintf (&new_options,
812 "%s%s%s",
813 fin_options,
814 sl->name,
815 optpos + 2);
816 GNUNET_free (fin_options);
817 fin_options = new_options;
818 }
819 if (NULL != options)
820 {
821 /* combine "fin_options" with "options" */
822 optpos = options;
824 "%s %s",
825 fin_options,
826 optpos);
827 GNUNET_free (fin_options);
828 GNUNET_free (optpos);
829 }
830 else
831 {
832 /* only have "fin_options", use that */
833 options = fin_options;
834 }
835 }
837 options);
839 sl->name,
840 "DEBUG");
841 {
842 const char *service_type = NULL;
843 const char *choices[] = {
844 "GNUNET",
845 "SIMPLE",
846 NULL
847 };
848
849 is_simple_service = false;
850 if ( (GNUNET_OK ==
852 sl->name,
853 "TYPE",
854 choices,
855 &service_type)) &&
856 (0 == strcasecmp (service_type,
857 "SIMPLE")) )
858 is_simple_service = true;
859 }
860
861 if (is_simple_service)
862 {
863 /* A simple service will receive no GNUnet specific
864 command line options. */
865 binary = GNUNET_strdup (sl->binary);
867 binary);
869 "Starting simple service `%s' using binary `%s'\n",
870 sl->name,
871 sl->binary);
873 loprefix,
874 binary,
875 options,
876 NULL);
877 }
878 else
879 {
880 char *command;
881
882 /* actually start process */
884 "Starting service `%s' using binary `%s' and configuration `%s'\n",
885 sl->name,
886 sl->binary,
887 sl->config);
890 sl->binary);
891 GNUNET_asprintf (&command,
892 "%s%s%s%s%s%s%s%s",
893 loprefix,
894 (0 == strlen (loprefix)) ? "" : " ",
895 binary,
896 (use_debug) ? " -L DEBUG" : "",
897 (NULL == sl->config) ? "" : " -c ",
898 (NULL == sl->config) ? "" : sl->config,
899 (0 == strlen (options)) ? "" : " ",
900 options);
902 "Launching GNUnet service `%s'\n",
903 command);
905 sl->proc,
906 command);
907 GNUNET_free (command);
908 }
909
910 if ( (GNUNET_OK != ret) ||
911 (GNUNET_OK !=
912 GNUNET_process_start (sl->proc) ) )
913 {
914 GNUNET_break (0);
915 goto failure;
916 }
917
920 "Starting service `%s'\n",
921 sl->name);
924 NULL);
925 if (client)
926 signal_result (client,
927 sl->name,
928 request_id,
930 goto cleanup;
931failure:
932 if (NULL != sl->proc)
933 {
935 sl->proc = NULL;
936 }
938 "Failed to start service `%s'\n",
939 sl->name);
940 if (client)
941 signal_result (client,
942 sl->name,
943 request_id,
945cleanup:
946 GNUNET_free (binary);
947 GNUNET_free (loprefix);
949}

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_option_std_inheritance, GNUNET_process_set_command(), GNUNET_process_set_command_va(), GNUNET_process_set_options, GNUNET_process_start(), 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 960 of file gnunet-service-arm.c.

961{
962 struct ServiceList *sl;
963
964 sl = running_head;
965 while (sl != NULL)
966 {
967 if (0 == strcasecmp (sl->name, name))
968 return sl;
969 sl = sl->next;
970 }
971 return NULL;
972}

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

983{
984 struct ServiceListeningInfo *sli = cls;
985 struct ServiceList *sl = sli->sl;
986
987 sli->accept_task = NULL;
989 start_process (sl, NULL, 0);
990}

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

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

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

1132{
1135 GNUNET_assert (NULL == sl->listen_head);
1136 GNUNET_free (sl->config);
1137 GNUNET_free (sl->binary);
1138 GNUNET_free (sl->name);
1139 GNUNET_free (sl);
1140}

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

1153{
1154 (void) cls;
1156 return GNUNET_OK;
1157}

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

1168{
1169 struct GNUNET_SERVICE_Client *client = cls;
1170 const char *servicename;
1171 struct ServiceList *sl;
1172 uint64_t request_id;
1173
1174 request_id = GNUNET_ntohll (amsg->request_id);
1175 servicename = (const char *) &amsg[1];
1177 if (GNUNET_YES == in_shutdown)
1178 {
1179 signal_result (client,
1180 servicename,
1181 request_id,
1183 return;
1184 }
1185 sl = find_service (servicename);
1186 if (NULL == sl)
1187 {
1188 signal_result (client,
1189 servicename,
1190 request_id,
1192 return;
1193 }
1194 sl->force_start = GNUNET_YES;
1195 if (NULL != sl->proc)
1196 {
1197 signal_result (client,
1198 servicename,
1199 request_id,
1201 return;
1202 }
1203 start_process (sl, client, request_id);
1204}

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

1214{
1215 (void) cls;
1216 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Triggering shutdown\n");
1218}

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

1232{
1233 (void) cls;
1235 return GNUNET_OK;
1236}

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

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

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

1339{
1340 size_t next_pos = (*pool_pos) + strlen (str) + 1;
1341
1342 if (next_pos > pool_size)
1343 return GNUNET_SYSERR;
1344 memcpy (pool_start + *pool_pos, str, strlen (str) + 1);
1345 *pool_pos = next_pos;
1346 return GNUNET_OK;
1347}

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

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

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

1445{
1446 struct GNUNET_SERVICE_Client *client = cls;
1447 struct GNUNET_MQ_Envelope *env;
1448 struct GNUNET_MessageHeader *msg;
1449
1450 (void) message;
1454}

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

1463{
1464 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Last shutdown phase\n");
1465 if (NULL != notifier)
1466 {
1468 notifier = NULL;
1469 }
1470 if (NULL != service)
1471 {
1473 service = NULL;
1474 }
1475 if (NULL != child_death_task)
1476 {
1478 child_death_task = NULL;
1479 }
1480}

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

1491{
1492 struct ServiceList *i;
1493 unsigned int res;
1494
1495 for (res = 0, i = run_head; NULL != i; i = i->next, res++)
1497 return res;
1498}

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

1508{
1509 struct ServiceList *pos;
1510 struct ServiceList *nxt;
1511 struct ServiceListeningInfo *sli;
1512
1513 (void) cls;
1514 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "First shutdown phase\n");
1515 if (NULL != child_restart_task)
1516 {
1518 child_restart_task = NULL;
1519 }
1521 /* first, stop listening */
1522 for (pos = running_head; NULL != pos; pos = pos->next)
1523 {
1524 while (NULL != (sli = pos->listen_head))
1525 {
1527 pos->listen_tail,
1528 sli);
1529 if (NULL != sli->accept_task)
1530 {
1532 sli->accept_task = NULL;
1533 }
1537 GNUNET_free (sli);
1538 }
1539 }
1540 /* then, shutdown all existing service processes */
1541 nxt = running_head;
1542 while (NULL != (pos = nxt))
1543 {
1544 nxt = pos->next;
1545 if (NULL != pos->proc)
1546 {
1548 "Stopping service `%s'\n",
1549 pos->name);
1551 if (GNUNET_OK !=
1555 "kill");
1556 }
1557 else
1558 {
1559 free_service (pos);
1560 }
1561 }
1562 /* finally, should all service processes be already gone, terminate for real */
1563 if (NULL == running_head)
1564 do_shutdown ();
1565 else
1567 "Delaying shutdown, have %u children still running\n",
1569}

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

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

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

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

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

1880{
1881 static char c;
1882 int old_errno = errno; /* back-up errno */
1883
1884 GNUNET_break (
1885 1 ==
1888 ,
1889 &c,
1890 sizeof(c)));
1891 errno = old_errno; /* restore errno */
1892}

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

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

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

2037{
2038 /* All clients are considered to be of the "monitor" kind
2039 * (that is, they don't affect ARM shutdown).
2040 */
2041 (void) cls;
2042 (void) mq;
2044 return client;
2045}

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

2059{
2060 (void) cls;
2061 GNUNET_assert (client == app_ctx);
2062 for (struct ServiceList *sl = running_head; NULL != sl; sl = sl->next)
2063 if (sl->killing_client == client)
2064 sl->killing_client = NULL;
2065}

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

2079{
2080 struct GNUNET_SERVICE_Client *client = cls;
2081
2082 (void) message;
2083 /* FIXME: might want to start by letting monitor know about
2084 services that are already running */
2085 /* Removal is handled by the server implementation, internally. */
2088 broadcast_status ("arm",
2090 client);
2092}

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

2106{
2107 struct ServiceList *sl;
2108 enum GNUNET_GenericReturnValue ret1;
2109 enum GNUNET_GenericReturnValue ret2;
2110
2111 (void) cls;
2112 cfg = c;
2113 service = serv;
2115 NULL);
2121 NULL);
2122#if HAVE_WAIT4
2123 if (GNUNET_OK ==
2125 "ARM",
2126 "RESOURCE_DIAGNOSTICS",
2127 &wait_filename))
2128 {
2129 wait_file = fopen (wait_filename, "w");
2130 if (NULL == wait_file)
2131 {
2133 "fopen",
2134 wait_filename);
2135 }
2136 }
2137#endif
2138 if (GNUNET_OK !=
2140 "ARM",
2141 "GLOBAL_PREFIX",
2144 else
2147 if (GNUNET_OK !=
2149 "ARM",
2150 "GLOBAL_POSTFIX",
2151 &final_option))
2153 else
2155 final_option);
2157 "ARM",
2158 "START_SYSTEM_SERVICES");
2160 "ARM",
2161 "START_USER_SERVICES");
2162 if ( (GNUNET_SYSERR == ret1) ||
2163 (GNUNET_SYSERR == ret2) )
2164 {
2165 /* invalid option */
2166 GNUNET_break (0);
2168 global_ret = 1;
2169 return;
2170 }
2172 "ARM",
2173 "START_SYSTEM_SERVICES"))
2174 ret1 = GNUNET_SYSERR;
2176 "ARM",
2177 "START_USER_SERVICES"))
2178 ret2 = GNUNET_SYSERR;
2179 start_system = (GNUNET_YES == ret1) ||
2180 ( (GNUNET_SYSERR == ret1) && (GNUNET_SYSERR == ret2) );
2181 start_user = (GNUNET_YES == ret2) ||
2182 ( (GNUNET_SYSERR == ret1) && (GNUNET_SYSERR == ret2) );
2183 if ( (GNUNET_NO == start_user) &&
2184 (GNUNET_NO == start_system) )
2185 {
2186 GNUNET_log (
2188 "Please enable either START_USER_SERVICES or START_SYSTEM_SERVICES\n");
2190 global_ret = 1;
2191 return;
2192 }
2195 NULL);
2196
2197 /* start default services... */
2198 for (sl = running_head; NULL != sl; sl = sl->next)
2199 if (GNUNET_YES == sl->force_start)
2200 start_process (sl, NULL, 0);
2202}

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

2214{
2219 struct GNUNET_ARM_Message,
2220 NULL),
2223 struct GNUNET_ARM_Message,
2224 NULL),
2227 struct GNUNET_MessageHeader,
2228 NULL),
2231 struct GNUNET_ARM_Message,
2232 NULL),
2235 struct GNUNET_MessageHeader,
2236 NULL),
2238 };
2239
2241 GNUNET_assert (NULL != sigpipe);
2242 shc_chld =
2245 if (0 !=
2247 argc,
2248 argv,
2249 "arm",
2252 &run,
2255 NULL,
2256 handlers))
2257 global_ret = 2;
2258#if HAVE_WAIT4
2259 if (NULL != wait_file)
2260 {
2261 fclose (wait_file);
2262 wait_file = NULL;
2263 }
2264 if (NULL != wait_filename)
2265 {
2266 GNUNET_free (wait_filename);
2267 wait_filename = NULL;
2268 }
2269#endif
2271 shc_chld = NULL;
2273 sigpipe = NULL;
2274 return global_ret;
2275}

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

Here is the call graph for this function:

Variable Documentation

◆ running_head

struct ServiceList* running_head
static

◆ running_tail

struct ServiceList* running_tail
static

List of running services.

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

Referenced by free_service(), and setup_service().

◆ cfg

const struct GNUNET_CONFIGURATION_Handle* cfg
static

Our configuration.

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

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

◆ prefix_command

char* prefix_command
static

Command to prepend to each actual command.

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

Referenced by run(), and start_process().

◆ final_option

char* final_option
static

Option to append to each actual command.

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

Referenced by run(), and start_process().

◆ child_death_task

struct GNUNET_SCHEDULER_Task* child_death_task
static

ID of task called whenever we get a SIGCHILD.

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

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

◆ child_restart_task

struct GNUNET_SCHEDULER_Task* child_restart_task
static

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

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

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

◆ sigpipe

struct GNUNET_DISK_PipeHandle* sigpipe
static

Pipe used to communicate shutdown via signal.

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

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

◆ in_shutdown

int in_shutdown
static

◆ global_ret

int global_ret
static

Return value from main.

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

Referenced by main(), and run().

◆ start_user

int start_user = GNUNET_YES
static

Are we starting user services?

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

Referenced by run(), and setup_service().

◆ start_system

int start_system = GNUNET_YES
static

Are we starting system services?

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

Referenced by run(), and setup_service().

◆ service

struct GNUNET_SERVICE_Handle* service
static

Handle to our service instance.

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

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

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

◆ notifier

struct GNUNET_NotificationContext* notifier
static

Context for notifications we need to send to our clients.

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

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