2 This file is part of GNUnet.
3 Copyright (C) 2009-2011, 2015, 2016 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * @file arm/gnunet-service-arm.c
21 * @brief the automated restart manager service
22 * @author Christian Grothoff
25 #include "gnunet_util_lib.h"
26 #include "gnunet_arm_service.h"
27 #include "gnunet_protocols.h"
30 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
32 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
37 * Name of the file for writing resource utilization summaries to.
39 static char *wait_filename;
42 * Handle for the file for writing resource summaries.
44 static FILE *wait_file;
49 * How many messages do we queue up at most for optional
50 * notifications to a client? (this can cause notifications
51 * about outgoing messages to be dropped).
53 #define MAX_NOTIFY_QUEUE 1024
57 * List of our services.
63 * Record with information about a listen socket we have open.
65 struct ServiceListeningInfo
68 * This is a linked list.
70 struct ServiceListeningInfo *next;
73 * This is a linked list.
75 struct ServiceListeningInfo *prev;
78 * Address this socket is listening on.
80 struct sockaddr *service_addr;
83 * Service this listen socket is for.
85 struct ServiceList *sl;
88 * Number of bytes in @e service_addr
90 socklen_t service_addr_len;
93 * Our listening socket.
95 struct GNUNET_NETWORK_Handle *listen_socket;
98 * Task doing the accepting.
100 struct GNUNET_SCHEDULER_Task *accept_task;
106 * List of our services.
111 * This is a doubly-linked list.
113 struct ServiceList *next;
116 * This is a doubly-linked list.
118 struct ServiceList *prev;
121 * Linked list of listen sockets associated with this service.
123 struct ServiceListeningInfo *listen_head;
126 * Linked list of listen sockets associated with this service.
128 struct ServiceListeningInfo *listen_tail;
131 * Name of the service.
136 * Name of the binary used.
141 * Name of the configuration file used.
146 * Client to notify upon kill completion (waitpid), NULL
147 * if we should simply restart the process.
149 struct GNUNET_SERVICE_Client *killing_client;
152 * ID of the request that killed the service (for reporting back).
154 uint64_t killing_client_request_id;
157 * Process structure pointer of the child.
159 struct GNUNET_OS_Process *proc;
162 * Process exponential backoff time
164 struct GNUNET_TIME_Relative backoff;
167 * Absolute time at which the process is scheduled to restart in case of death
169 struct GNUNET_TIME_Absolute restart_at;
172 * Time we asked the service to shut down (used to calculate time it took
173 * the service to terminate).
175 struct GNUNET_TIME_Absolute killed_at;
178 * Is this service to be started by default (or did a client tell us explicitly
179 * to start it)? #GNUNET_NO if the service is started only upon 'accept' on a
180 * listen socket or possibly explicitly by a client changing the value.
185 * Should we use pipes to signal this process? (YES for Java binaries and if we
192 * List of running services.
194 static struct ServiceList *running_head;
197 * List of running services.
199 static struct ServiceList *running_tail;
204 static const struct GNUNET_CONFIGURATION_Handle *cfg;
207 * Command to prepend to each actual command.
209 static char *prefix_command;
212 * Option to append to each actual command.
214 static char *final_option;
217 * ID of task called whenever we get a SIGCHILD.
219 static struct GNUNET_SCHEDULER_Task *child_death_task;
222 * ID of task called whenever the timeout for restarting a child
225 static struct GNUNET_SCHEDULER_Task *child_restart_task;
228 * Pipe used to communicate shutdown via signal.
230 static struct GNUNET_DISK_PipeHandle *sigpipe;
233 * Are we in shutdown mode?
235 static int in_shutdown;
238 * Are we starting user services?
240 static int start_user = GNUNET_YES;
243 * Are we starting system services?
245 static int start_system = GNUNET_YES;
248 * Handle to our service instance. Our service is a bit special in that
249 * its service is not immediately stopped once we get a shutdown
250 * request (since we need to continue service until all of our child
251 * processes are dead). This handle is used to shut down the service
252 * (and thus trigger process termination) once all child processes are
253 * also dead. A special option in the ARM configuration modifies the
254 * behaviour of the service implementation to not do the shutdown
257 static struct GNUNET_SERVICE_Handle *service;
260 * Context for notifications we need to send to our clients.
262 static struct GNUNET_NotificationContext *notifier;
266 * Add the given UNIX domain path as an address to the
267 * list (as the first entry).
269 * @param saddrs array to update
270 * @param saddrlens where to store the address length
271 * @param unixpath path to add
272 * @param abstract #GNUNET_YES to add an abstract UNIX domain socket. This
273 * parameter is ignore on systems other than LINUX
276 add_unixpath (struct sockaddr **saddrs,
277 socklen_t *saddrlens,
278 const char *unixpath,
282 struct sockaddr_un *un;
284 un = GNUNET_new (struct sockaddr_un);
285 un->sun_family = AF_UNIX;
286 strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
288 if (GNUNET_YES == abstract)
289 un->sun_path[0] = '\0';
291 #if HAVE_SOCKADDR_UN_SUN_LEN
292 un->sun_len = (u_char) sizeof (struct sockaddr_un);
294 *saddrs = (struct sockaddr *) un;
295 *saddrlens = sizeof (struct sockaddr_un);
297 /* this function should never be called
298 * unless AF_UNIX is defined! */
305 * Get the list of addresses that a server for the given service
308 * @param service_name name of the service
309 * @param cfg configuration (which specifies the addresses)
310 * @param addrs set (call by reference) to an array of pointers to the
311 * addresses the server should bind to and listen on; the
312 * array will be NULL-terminated (on success)
313 * @param addr_lens set (call by reference) to an array of the lengths
314 * of the respective `struct sockaddr` struct in the @a addrs
316 * @return number of addresses found on success,
317 * #GNUNET_SYSERR if the configuration
318 * did not specify reasonable finding information or
319 * if it specified a hostname that could not be resolved;
320 * #GNUNET_NO if the number of addresses configured is
321 * zero (in this case, `*addrs` and `*addr_lens` will be
325 get_server_addresses (const char *service_name,
326 const struct GNUNET_CONFIGURATION_Handle *cfg,
327 struct sockaddr ***addrs,
328 socklen_t ** addr_lens)
331 struct GNUNET_NETWORK_Handle *desc;
332 unsigned long long port;
334 struct addrinfo hints;
335 struct addrinfo *res;
336 struct addrinfo *pos;
337 struct addrinfo *next;
342 struct sockaddr **saddrs;
343 socklen_t *saddrlens;
349 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
353 GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
354 return GNUNET_SYSERR;
357 disablev6 = GNUNET_NO;
361 /* probe IPv6 support */
362 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
365 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
368 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
369 return GNUNET_SYSERR;
371 LOG (GNUNET_ERROR_TYPE_INFO,
372 _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
373 service_name, STRERROR (errno));
374 disablev6 = GNUNET_YES;
378 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
384 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
387 GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
390 LOG (GNUNET_ERROR_TYPE_ERROR,
391 _("Require valid port number for service `%s' in configuration!\n"),
396 LOG (GNUNET_ERROR_TYPE_ERROR,
397 _("Require valid port number for service `%s' in configuration!\n"),
399 return GNUNET_SYSERR;
403 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
405 GNUNET_break (GNUNET_OK ==
406 GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
407 "BINDTO", &hostname));
413 abstract = GNUNET_NO;
416 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
418 GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
420 (0 < strlen (unixpath)))
422 /* probe UNIX support */
423 struct sockaddr_un s_un;
425 if (strlen (unixpath) >= sizeof (s_un.sun_path))
427 LOG (GNUNET_ERROR_TYPE_WARNING,
428 _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
429 (unsigned long long) sizeof (s_un.sun_path));
430 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
431 LOG (GNUNET_ERROR_TYPE_INFO,
432 _("Using `%s' instead\n"),
436 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
438 "USE_ABSTRACT_SOCKETS");
439 if (GNUNET_SYSERR == abstract)
440 abstract = GNUNET_NO;
442 if ((GNUNET_YES != abstract)
444 GNUNET_DISK_directory_create_for_file (unixpath)))
445 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
449 if (NULL != unixpath)
451 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
454 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
457 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
458 GNUNET_free_non_null (hostname);
459 GNUNET_free (unixpath);
460 return GNUNET_SYSERR;
462 LOG (GNUNET_ERROR_TYPE_INFO,
463 _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
466 GNUNET_free (unixpath);
471 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
477 if ((0 == port) && (NULL == unixpath))
479 LOG (GNUNET_ERROR_TYPE_ERROR,
480 _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
482 GNUNET_free_non_null (hostname);
483 return GNUNET_SYSERR;
487 saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
488 saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
489 add_unixpath (saddrs, saddrlens, unixpath, abstract);
490 GNUNET_free_non_null (unixpath);
491 GNUNET_free_non_null (hostname);
493 *addr_lens = saddrlens;
497 if (NULL != hostname)
499 LOG (GNUNET_ERROR_TYPE_DEBUG,
500 "Resolving `%s' since that is where `%s' will bind to.\n",
503 memset (&hints, 0, sizeof (struct addrinfo));
505 hints.ai_family = AF_INET;
506 hints.ai_protocol = IPPROTO_TCP;
507 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
510 LOG (GNUNET_ERROR_TYPE_ERROR,
511 _("Failed to resolve `%s': %s\n"),
514 GNUNET_free (hostname);
515 GNUNET_free_non_null (unixpath);
516 return GNUNET_SYSERR;
520 while (NULL != (pos = next))
523 if ((disablev6) && (pos->ai_family == AF_INET6))
529 LOG (GNUNET_ERROR_TYPE_ERROR,
530 _("Failed to find %saddress for `%s'.\n"),
531 disablev6 ? "IPv4 " : "",
534 GNUNET_free (hostname);
535 GNUNET_free_non_null (unixpath);
536 return GNUNET_SYSERR;
539 if (NULL != unixpath)
541 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
542 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
544 if (NULL != unixpath)
546 add_unixpath (saddrs, saddrlens, unixpath, abstract);
550 while (NULL != (pos = next))
553 if ((disablev6) && (AF_INET6 == pos->ai_family))
555 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
556 continue; /* not TCP */
557 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
559 LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
560 service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
561 if (AF_INET == pos->ai_family)
563 GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
564 saddrlens[i] = pos->ai_addrlen;
565 saddrs[i] = GNUNET_malloc (saddrlens[i]);
566 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
567 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
571 GNUNET_assert (AF_INET6 == pos->ai_family);
572 GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
573 saddrlens[i] = pos->ai_addrlen;
574 saddrs[i] = GNUNET_malloc (saddrlens[i]);
575 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
576 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
580 GNUNET_free (hostname);
586 /* will bind against everything, just set port */
591 if (NULL != unixpath)
594 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
595 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
596 if (NULL != unixpath)
598 add_unixpath (saddrs, saddrlens, unixpath, abstract);
601 saddrlens[i] = sizeof (struct sockaddr_in);
602 saddrs[i] = GNUNET_malloc (saddrlens[i]);
603 #if HAVE_SOCKADDR_IN_SIN_LEN
604 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
606 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
607 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
613 if (NULL != unixpath)
615 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
616 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
618 if (NULL != unixpath)
620 add_unixpath (saddrs, saddrlens, unixpath, abstract);
623 saddrlens[i] = sizeof (struct sockaddr_in6);
624 saddrs[i] = GNUNET_malloc (saddrlens[i]);
625 #if HAVE_SOCKADDR_IN_SIN_LEN
626 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
628 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
629 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
631 saddrlens[i] = sizeof (struct sockaddr_in);
632 saddrs[i] = GNUNET_malloc (saddrlens[i]);
633 #if HAVE_SOCKADDR_IN_SIN_LEN
634 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
636 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
637 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
640 GNUNET_free_non_null (unixpath);
642 *addr_lens = saddrlens;
648 * Signal our client that we will start or stop the
651 * @param client who is being signalled
652 * @param name name of the service
653 * @param request_id id of the request that is being responded to.
654 * @param result message type to send
655 * @return NULL if it was not found
658 signal_result (struct GNUNET_SERVICE_Client *client,
661 enum GNUNET_ARM_Result result)
663 struct GNUNET_MQ_Envelope *env;
664 struct GNUNET_ARM_ResultMessage *msg;
666 env = GNUNET_MQ_msg (msg,
667 GNUNET_MESSAGE_TYPE_ARM_RESULT);
668 msg->result = htonl (result);
669 msg->arm_msg.request_id = GNUNET_htonll (request_id);
670 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
676 * Tell all clients about status change of a service.
678 * @param name name of the service
679 * @param status message type to send
680 * @param unicast if not NULL, send to this client only.
681 * otherwise, send to all clients in the notifier
684 broadcast_status (const char *name,
685 enum GNUNET_ARM_ServiceStatus status,
686 struct GNUNET_SERVICE_Client *unicast)
688 struct GNUNET_MQ_Envelope *env;
689 struct GNUNET_ARM_StatusMessage *msg;
692 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
693 "Sending status %u of service `%s' to client\n",
694 (unsigned int) status,
696 namelen = strlen (name) + 1;
697 env = GNUNET_MQ_msg_extra (msg,
699 GNUNET_MESSAGE_TYPE_ARM_STATUS);
700 msg->status = htonl ((uint32_t) (status));
701 GNUNET_memcpy ((char *) &msg[1],
706 if (NULL != notifier)
707 GNUNET_notification_context_broadcast (notifier,
710 GNUNET_MQ_discard (env);
714 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (unicast),
721 * Actually start the process for the given service.
723 * @param sl identifies service to start
724 * @param client that asked to start the service (may be NULL)
725 * @param request_id id of the request in response to which the process is
726 * being started. 0 if starting was not requested.
729 start_process (struct ServiceList *sl,
730 struct GNUNET_SERVICE_Client *client,
736 int is_simple_service;
737 struct ServiceListeningInfo *sli;
743 /* calculate listen socket list */
746 for (sli = sl->listen_head; NULL != sli; sli = sli->next)
748 GNUNET_array_append (lsocks, ls,
749 GNUNET_NETWORK_get_fd (sli->listen_socket));
750 if (NULL != sli->accept_task)
752 GNUNET_SCHEDULER_cancel (sli->accept_task);
753 sli->accept_task = NULL;
757 GNUNET_array_append (lsocks,
761 GNUNET_array_append (lsocks,
766 /* obtain configuration */
768 GNUNET_CONFIGURATION_get_value_string (cfg,
772 loprefix = GNUNET_strdup (prefix_command);
774 loprefix = GNUNET_CONFIGURATION_expand_dollar (cfg,
777 GNUNET_CONFIGURATION_get_value_string (cfg,
783 options = GNUNET_CONFIGURATION_expand_dollar (cfg,
790 fin_options = GNUNET_strdup (final_option);
791 /* replace '{}' with service name */
792 while (NULL != (optpos = strstr (fin_options,
795 /* terminate string at opening parenthesis */
797 GNUNET_asprintf (&new_options,
802 GNUNET_free (fin_options);
803 fin_options = new_options;
807 /* combine "fin_options" with "options" */
809 GNUNET_asprintf (&options,
813 GNUNET_free (fin_options);
814 GNUNET_free (optpos);
818 /* only have "fin_options", use that */
819 options = fin_options;
822 options = GNUNET_CONFIGURATION_expand_dollar (cfg,
824 use_debug = GNUNET_CONFIGURATION_get_value_yesno (cfg,
828 const char *service_type = NULL;
829 const char *choices[] = { "GNUNET", "SIMPLE", NULL };
831 is_simple_service = GNUNET_NO;
833 GNUNET_CONFIGURATION_get_value_choice (cfg,
838 (0 == strcasecmp (service_type, "SIMPLE")) )
839 is_simple_service = GNUNET_YES;
842 GNUNET_assert (NULL == sl->proc);
843 if (GNUNET_YES == is_simple_service)
845 /* A simple service will receive no GNUnet specific
846 command line options. */
847 binary = GNUNET_strdup (sl->binary);
848 binary = GNUNET_CONFIGURATION_expand_dollar (cfg, binary);
849 GNUNET_asprintf ("edbinary,
852 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
853 "Starting simple service `%s' using binary `%s'\n",
854 sl->name, sl->binary);
855 /* FIXME: dollar expansion should only be done outside
856 * of ''-quoted strings, escaping should be considered. */
858 options = GNUNET_CONFIGURATION_expand_dollar (cfg, options);
860 GNUNET_OS_start_process_s (sl->pipe_control,
861 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
870 /* actually start process */
871 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
872 "Starting service `%s' using binary `%s' and configuration `%s'\n",
873 sl->name, sl->binary, sl->config);
874 binary = GNUNET_OS_get_libexec_binary_path (sl->binary);
875 GNUNET_asprintf ("edbinary,
879 if (GNUNET_YES == use_debug)
881 if (NULL == sl->config)
883 GNUNET_OS_start_process_s (sl->pipe_control,
884 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
893 GNUNET_OS_start_process_s (sl->pipe_control,
894 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
905 if (NULL == sl->config)
907 GNUNET_OS_start_process_s (sl->pipe_control,
908 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
916 GNUNET_OS_start_process_s (sl->pipe_control,
917 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
926 GNUNET_free (binary);
927 GNUNET_free (quotedbinary);
928 if (NULL == sl->proc)
930 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
931 _("Failed to start service `%s'\n"),
934 signal_result (client,
937 GNUNET_ARM_RESULT_START_FAILED);
941 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
942 _("Starting service `%s'\n"),
944 broadcast_status (sl->name,
945 GNUNET_ARM_SERVICE_STARTING,
948 signal_result (client,
951 GNUNET_ARM_RESULT_STARTING);
954 GNUNET_free (loprefix);
955 GNUNET_free (options);
956 GNUNET_array_grow (lsocks,
963 * Find the process with the given service
964 * name in the given list and return it.
966 * @param name which service entry to look up
967 * @return NULL if it was not found
969 static struct ServiceList *
970 find_service (const char *name)
972 struct ServiceList *sl;
977 if (0 == strcasecmp (sl->name, name))
986 * First connection has come to the listening socket associated with the service,
987 * create the service in order to relay the incoming connection to it
989 * @param cls callback data, `struct ServiceListeningInfo` describing a listen socket
992 accept_connection (void *cls)
994 struct ServiceListeningInfo *sli = cls;
995 struct ServiceList *sl = sli->sl;
997 sli->accept_task = NULL;
998 GNUNET_assert (GNUNET_NO == in_shutdown);
999 start_process (sl, NULL, 0);
1004 * Creating a listening socket for each of the service's addresses and
1005 * wait for the first incoming connection to it
1007 * @param sa address associated with the service
1008 * @param addr_len length of @a sa
1009 * @param sl service entry for the service in question
1012 create_listen_socket (struct sockaddr *sa,
1014 struct ServiceList *sl)
1017 struct GNUNET_NETWORK_Handle *sock;
1018 struct ServiceListeningInfo *sli;
1024 switch (sa->sa_family)
1027 sock = GNUNET_NETWORK_socket_create (PF_INET,
1032 sock = GNUNET_NETWORK_socket_create (PF_INET6,
1037 if (0 == strcmp (GNUNET_a2s (sa,
1039 "@")) /* Do not bind to blank UNIX path! */
1041 sock = GNUNET_NETWORK_socket_create (PF_UNIX,
1048 errno = EAFNOSUPPORT;
1053 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1054 _("Unable to create socket for service `%s': %s\n"),
1061 GNUNET_NETWORK_socket_setsockopt (sock,
1066 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1069 if ( (sa->sa_family == AF_INET6) &&
1071 GNUNET_NETWORK_socket_setsockopt (sock,
1076 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1080 if (AF_UNIX == sa->sa_family)
1081 GNUNET_NETWORK_unix_precheck ((struct sockaddr_un *) sa);
1084 GNUNET_NETWORK_socket_bind (sock,
1085 (const struct sockaddr *) sa,
1088 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1089 _("Unable to bind listening socket for service `%s' to address `%s': %s\n"),
1094 GNUNET_break (GNUNET_OK ==
1095 GNUNET_NETWORK_socket_close (sock));
1100 if ((AF_UNIX == sa->sa_family)
1102 /* Permission settings are not required when abstract sockets are used */
1103 && ('\0' != ((const struct sockaddr_un *)sa)->sun_path[0])
1108 GNUNET_CONFIGURATION_get_value_yesno (cfg,
1112 GNUNET_CONFIGURATION_get_value_yesno (cfg,
1115 GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sa)->sun_path,
1122 GNUNET_NETWORK_socket_listen (sock, 5))
1124 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1126 GNUNET_break (GNUNET_OK ==
1127 GNUNET_NETWORK_socket_close (sock));
1131 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1132 _("ARM now monitors connections to service `%s' at `%s'\n"),
1136 sli = GNUNET_new (struct ServiceListeningInfo);
1137 sli->service_addr = sa;
1138 sli->service_addr_len = addr_len;
1139 sli->listen_socket = sock;
1142 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1144 &accept_connection, sli);
1145 GNUNET_CONTAINER_DLL_insert (sl->listen_head,
1152 * Remove and free an entry in the service list. Listen sockets
1153 * must have already been cleaned up. Only to be called during shutdown.
1155 * @param sl entry to free
1158 free_service (struct ServiceList *sl)
1160 GNUNET_assert (GNUNET_YES == in_shutdown);
1161 GNUNET_CONTAINER_DLL_remove (running_head,
1164 GNUNET_assert (NULL == sl->listen_head);
1165 GNUNET_free_non_null (sl->config);
1166 GNUNET_free_non_null (sl->binary);
1167 GNUNET_free (sl->name);
1173 * Check START-message.
1175 * @param cls identification of the client
1176 * @param amsg the actual message
1177 * @return #GNUNET_OK to keep the connection open,
1178 * #GNUNET_SYSERR to close it (signal serious error)
1181 check_start (void *cls,
1182 const struct GNUNET_ARM_Message *amsg)
1185 const char *servicename;
1187 size = ntohs (amsg->header.size) - sizeof (struct GNUNET_ARM_Message);
1188 servicename = (const char *) &amsg[1];
1190 (servicename[size - 1] != '\0') )
1193 return GNUNET_SYSERR;
1200 * Handle START-message.
1202 * @param cls identification of the client
1203 * @param amsg the actual message
1206 handle_start (void *cls,
1207 const struct GNUNET_ARM_Message *amsg)
1209 struct GNUNET_SERVICE_Client *client = cls;
1210 const char *servicename;
1211 struct ServiceList *sl;
1212 uint64_t request_id;
1214 request_id = GNUNET_ntohll (amsg->request_id);
1215 servicename = (const char *) &amsg[1];
1216 GNUNET_SERVICE_client_continue (client);
1217 if (GNUNET_YES == in_shutdown)
1219 signal_result (client,
1222 GNUNET_ARM_RESULT_IN_SHUTDOWN);
1225 sl = find_service (servicename);
1228 signal_result (client,
1231 GNUNET_ARM_RESULT_IS_NOT_KNOWN);
1234 sl->force_start = GNUNET_YES;
1235 if (NULL != sl->proc)
1237 signal_result (client,
1240 GNUNET_ARM_RESULT_IS_STARTED_ALREADY);
1250 * Start a shutdown sequence.
1252 * @param cls closure (refers to service)
1255 trigger_shutdown (void *cls)
1257 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1258 "Triggering shutdown\n");
1259 GNUNET_SCHEDULER_shutdown ();
1264 * Check STOP-message.
1266 * @param cls identification of the client
1267 * @param amsg the actual message
1268 * @return #GNUNET_OK to keep the connection open,
1269 * #GNUNET_SYSERR to close it (signal serious error)
1272 check_stop (void *cls,
1273 const struct GNUNET_ARM_Message *amsg)
1276 const char *servicename;
1278 size = ntohs (amsg->header.size) - sizeof (struct GNUNET_ARM_Message);
1279 servicename = (const char *) &amsg[1];
1281 (servicename[size - 1] != '\0') )
1284 return GNUNET_SYSERR;
1291 * Handle STOP-message.
1293 * @param cls identification of the client
1294 * @param amsg the actual message
1297 handle_stop (void *cls,
1298 const struct GNUNET_ARM_Message *amsg)
1300 struct GNUNET_SERVICE_Client *client = cls;
1301 struct ServiceList *sl;
1302 const char *servicename;
1303 uint64_t request_id;
1305 request_id = GNUNET_ntohll (amsg->request_id);
1306 servicename = (const char *) &amsg[1];
1307 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1308 _("Preparing to stop `%s'\n"),
1310 GNUNET_SERVICE_client_continue (client);
1311 if (0 == strcasecmp (servicename,
1314 broadcast_status (servicename,
1315 GNUNET_ARM_SERVICE_STOPPING,
1317 signal_result (client,
1320 GNUNET_ARM_RESULT_STOPPING);
1321 GNUNET_SERVICE_client_persist (client);
1322 GNUNET_SCHEDULER_add_now (&trigger_shutdown,
1326 sl = find_service (servicename);
1329 signal_result (client,
1332 GNUNET_ARM_RESULT_IS_NOT_KNOWN);
1335 sl->force_start = GNUNET_NO;
1336 if (GNUNET_YES == in_shutdown)
1338 /* shutdown in progress */
1339 signal_result (client,
1342 GNUNET_ARM_RESULT_IN_SHUTDOWN);
1345 if (NULL != sl->killing_client)
1347 /* killing already in progress */
1348 signal_result (client,
1351 GNUNET_ARM_RESULT_IS_STOPPING_ALREADY);
1354 if (NULL == sl->proc)
1356 /* process is down */
1357 signal_result (client,
1360 GNUNET_ARM_RESULT_IS_STOPPED_ALREADY);
1363 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1364 "Sending kill signal to service `%s', waiting for process to die.\n",
1366 broadcast_status (servicename,
1367 GNUNET_ARM_SERVICE_STOPPING,
1369 /* no signal_start - only when it's STOPPED */
1370 sl->killed_at = GNUNET_TIME_absolute_get ();
1371 if (0 != GNUNET_OS_process_kill (sl->proc,
1373 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1375 sl->killing_client = client;
1376 sl->killing_client_request_id = request_id;
1381 * Handle LIST-message.
1383 * @param cls identification of the client
1384 * @param message the actual message
1387 handle_list (void *cls,
1388 const struct GNUNET_ARM_Message *request)
1390 struct GNUNET_SERVICE_Client *client = cls;
1391 struct GNUNET_MQ_Envelope *env;
1392 struct GNUNET_ARM_ListResultMessage *msg;
1393 size_t string_list_size;
1394 struct ServiceList *sl;
1398 GNUNET_break (0 == ntohl (request->reserved));
1400 string_list_size = 0;
1402 /* first count the running processes get their name's size */
1403 for (sl = running_head; NULL != sl; sl = sl->next)
1405 if (NULL != sl->proc)
1407 string_list_size += strlen (sl->name);
1408 string_list_size += strlen (sl->binary);
1409 string_list_size += 4;
1414 env = GNUNET_MQ_msg_extra (msg,
1416 GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT);
1417 msg->arm_msg.request_id = request->request_id;
1418 msg->count = htons (count);
1420 pos = (char *) &msg[1];
1421 for (sl = running_head; NULL != sl; sl = sl->next)
1423 if (NULL != sl->proc)
1425 size_t s = strlen (sl->name) + strlen (sl->binary) + 4;
1426 GNUNET_snprintf (pos,
1434 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
1436 GNUNET_SERVICE_client_continue (client);
1441 * Handle TEST-message by sending back TEST.
1443 * @param cls identification of the client
1444 * @param message the actual message
1447 handle_test (void *cls,
1448 const struct GNUNET_MessageHeader *message)
1450 struct GNUNET_SERVICE_Client *client = cls;
1451 struct GNUNET_MQ_Envelope *env;
1452 struct GNUNET_MessageHeader *msg;
1454 env = GNUNET_MQ_msg (msg,
1455 GNUNET_MESSAGE_TYPE_ARM_TEST);
1456 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
1458 GNUNET_SERVICE_client_continue (client);
1463 * We are done with everything. Stop remaining
1464 * tasks, signal handler and the server.
1469 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1470 "Last shutdown phase\n");
1471 if (NULL != notifier)
1473 GNUNET_notification_context_destroy (notifier);
1476 if (NULL != service)
1478 GNUNET_SERVICE_shutdown (service);
1481 if (NULL != child_death_task)
1483 GNUNET_SCHEDULER_cancel (child_death_task);
1484 child_death_task = NULL;
1490 * Count how many services are still active.
1492 * @param running_head list of services
1493 * @return number of active services found
1496 list_count (struct ServiceList *running_head)
1498 struct ServiceList *i;
1501 for (res = 0, i = running_head; i; i = i->next, res++)
1502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1510 * Task run for shutdown.
1512 * @param cls closure, NULL if we need to self-restart
1515 shutdown_task (void *cls)
1517 struct ServiceList *pos;
1518 struct ServiceList *nxt;
1519 struct ServiceListeningInfo *sli;
1521 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1522 "First shutdown phase\n");
1523 if (NULL != child_restart_task)
1525 GNUNET_SCHEDULER_cancel (child_restart_task);
1526 child_restart_task = NULL;
1528 in_shutdown = GNUNET_YES;
1529 /* first, stop listening */
1530 for (pos = running_head; NULL != pos; pos = pos->next)
1532 while (NULL != (sli = pos->listen_head))
1534 GNUNET_CONTAINER_DLL_remove (pos->listen_head,
1537 if (NULL != sli->accept_task)
1539 GNUNET_SCHEDULER_cancel (sli->accept_task);
1540 sli->accept_task = NULL;
1542 GNUNET_break (GNUNET_OK ==
1543 GNUNET_NETWORK_socket_close (sli->listen_socket));
1544 GNUNET_free (sli->service_addr);
1548 /* then, shutdown all existing service processes */
1550 while (NULL != (pos = nxt))
1553 if (NULL != pos->proc)
1555 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1556 "Stopping service `%s'\n",
1558 pos->killed_at = GNUNET_TIME_absolute_get ();
1559 if (0 != GNUNET_OS_process_kill (pos->proc,
1561 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1569 /* finally, should all service processes be already gone, terminate for real */
1570 if (NULL == running_head)
1573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1574 "Delaying shutdown, have %u childs still running\n",
1575 list_count (running_head));
1580 * Task run whenever it is time to restart a child that died.
1582 * @param cls closure, always NULL
1585 delayed_restart_task (void *cls)
1588 struct ServiceList *sl;
1589 struct GNUNET_TIME_Relative lowestRestartDelay;
1590 struct ServiceListeningInfo *sli;
1592 child_restart_task = NULL;
1593 GNUNET_assert (GNUNET_NO == in_shutdown);
1594 lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL;
1596 /* check for services that need to be restarted due to
1597 * configuration changes or because the last restart failed */
1598 for (sl = running_head; NULL != sl; sl = sl->next)
1600 if (NULL != sl->proc)
1602 /* service is currently not running */
1603 if (0 == GNUNET_TIME_absolute_get_remaining (sl->restart_at).rel_value_us)
1605 /* restart is now allowed */
1606 if (sl->force_start)
1608 /* process should run by default, start immediately */
1609 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1610 _("Restarting service `%s'.\n"),
1618 /* process is run on-demand, ensure it is re-started if there is demand */
1619 for (sli = sl->listen_head; NULL != sli; sli = sli->next)
1620 if (NULL == sli->accept_task)
1622 /* accept was actually paused, so start it again */
1624 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1633 /* update calculation for earliest time to reactivate a service */
1634 lowestRestartDelay =
1635 GNUNET_TIME_relative_min (lowestRestartDelay,
1636 GNUNET_TIME_absolute_get_remaining
1640 if (lowestRestartDelay.rel_value_us != GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1642 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1643 "Will restart process in %s\n",
1644 GNUNET_STRINGS_relative_time_to_string (lowestRestartDelay,
1646 child_restart_task =
1647 GNUNET_SCHEDULER_add_delayed_with_priority (lowestRestartDelay,
1648 GNUNET_SCHEDULER_PRIORITY_IDLE,
1649 &delayed_restart_task,
1656 * Task triggered whenever we receive a SIGCHLD (child
1659 * @param cls closure, NULL if we need to self-restart
1662 maint_child_death (void *cls)
1664 struct ServiceList *pos;
1665 struct ServiceList *next;
1666 struct ServiceListeningInfo *sli;
1667 const char *statstr;
1671 enum GNUNET_OS_ProcessStatusType statusType;
1672 unsigned long statusCode;
1673 const struct GNUNET_DISK_FileHandle *pr;
1675 pr = GNUNET_DISK_pipe_handle (sigpipe,
1676 GNUNET_DISK_PIPE_END_READ);
1677 child_death_task = NULL;
1678 /* consume the signal */
1679 GNUNET_break (0 < GNUNET_DISK_file_read (pr,
1683 /* check for services that died (WAITPID) */
1684 next = running_head;
1685 while (NULL != (pos = next))
1689 if (NULL == pos->proc)
1691 if (GNUNET_YES == in_shutdown)
1696 if (NULL != wait_file)
1698 /* need to use 'wait4()' to obtain and log performance data */
1703 pid = GNUNET_OS_process_get_pid (pos->proc);
1709 continue; /* no process done */
1710 if (WIFEXITED (status))
1712 statusType = GNUNET_OS_PROCESS_EXITED;
1713 statusCode = WEXITSTATUS (status);
1715 else if (WIFSIGNALED (status))
1717 statusType = GNUNET_OS_PROCESS_SIGNALED;
1718 statusCode = WTERMSIG (status);
1720 else if (WIFSTOPPED (status))
1722 statusType = GNUNET_OS_PROCESS_SIGNALED;
1723 statusCode = WSTOPSIG (status);
1726 else if (WIFCONTINUED (status))
1728 statusType = GNUNET_OS_PROCESS_RUNNING;
1734 statusType = GNUNET_OS_PROCESS_UNKNOWN;
1737 if ( (GNUNET_OS_PROCESS_EXITED == statusType) ||
1738 (GNUNET_OS_PROCESS_SIGNALED == statusType) )
1740 double utime = ru.ru_utime.tv_sec + (ru.ru_utime.tv_usec / 10e6);
1741 double stime = ru.ru_stime.tv_sec + (ru.ru_stime.tv_usec / 10e6);
1743 "%s(%u) %.3f %.3f %llu %llu %llu %llu %llu\n",
1748 (unsigned long long) ru.ru_maxrss,
1749 (unsigned long long) ru.ru_inblock,
1750 (unsigned long long) ru.ru_oublock,
1751 (unsigned long long) ru.ru_nvcsw,
1752 (unsigned long long) ru.ru_nivcsw);
1755 else /* continue with JUST this "if" as "else" (intentionally no brackets!) */
1757 if ( (GNUNET_SYSERR ==
1759 GNUNET_OS_process_status (pos->proc,
1762 (ret == GNUNET_NO) ||
1763 (statusType == GNUNET_OS_PROCESS_STOPPED) ||
1764 (statusType == GNUNET_OS_PROCESS_UNKNOWN) ||
1765 (statusType == GNUNET_OS_PROCESS_RUNNING) )
1768 if (statusType == GNUNET_OS_PROCESS_EXITED)
1770 statstr = _( /* process termination method */ "exit");
1771 statcode = statusCode;
1773 else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
1775 statstr = _( /* process termination method */ "signal");
1776 statcode = statusCode;
1780 statstr = _( /* process termination method */ "unknown");
1783 if (0 != pos->killed_at.abs_value_us)
1785 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1786 _("Service `%s' took %s to terminate\n"),
1788 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->killed_at),
1791 GNUNET_OS_process_destroy (pos->proc);
1793 broadcast_status (pos->name,
1794 GNUNET_ARM_SERVICE_STOPPED,
1796 if (NULL != pos->killing_client)
1798 signal_result (pos->killing_client, pos->name,
1799 pos->killing_client_request_id,
1800 GNUNET_ARM_RESULT_STOPPED);
1801 pos->killing_client = NULL;
1802 pos->killing_client_request_id = 0;
1804 if (GNUNET_YES != in_shutdown)
1806 if ( (statusType == GNUNET_OS_PROCESS_EXITED) &&
1809 /* process terminated normally, allow restart at any time */
1810 pos->restart_at.abs_value_us = 0;
1811 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1812 _("Service `%s' terminated normally, will restart at any time\n"),
1814 /* process can still be re-started on-demand, ensure it is re-started if there is demand */
1815 for (sli = pos->listen_head; NULL != sli; sli = sli->next)
1817 GNUNET_break (NULL == sli->accept_task);
1819 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1827 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1828 _("Service `%s' terminated with status %s/%d, will restart in %s\n"),
1832 GNUNET_STRINGS_relative_time_to_string (pos->backoff,
1835 /* Reduce backoff based on runtime of the process,
1836 so that there is a cool-down if a process actually
1837 runs for a while. */
1838 struct GNUNET_TIME_Relative runtime;
1839 unsigned int minutes;
1841 runtime = GNUNET_TIME_absolute_get_duration (pos->restart_at);
1842 minutes = runtime.rel_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us;
1844 pos->backoff = GNUNET_TIME_UNIT_ZERO;
1846 pos->backoff.rel_value_us <<= minutes;
1848 /* schedule restart */
1849 pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff);
1850 pos->backoff = GNUNET_TIME_STD_BACKOFF (pos->backoff);
1851 if (NULL != child_restart_task)
1852 GNUNET_SCHEDULER_cancel (child_restart_task);
1854 = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
1855 &delayed_restart_task,
1864 child_death_task = GNUNET_SCHEDULER_add_read_file (
1865 GNUNET_TIME_UNIT_FOREVER_REL,
1867 &maint_child_death, NULL);
1868 if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
1870 else if (GNUNET_YES == in_shutdown)
1871 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1872 "Delaying shutdown after child's death, still have %u children\n",
1873 list_count (running_head));
1879 * Signal handler called for SIGCHLD. Triggers the
1880 * respective handler by writing to the trigger pipe.
1883 sighandler_child_death ()
1886 int old_errno = errno; /* back-up errno */
1889 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (sigpipe,
1890 GNUNET_DISK_PIPE_END_WRITE),
1893 errno = old_errno; /* restore errno */
1898 * Setup our service record for the given section in the configuration file
1899 * (assuming the section is for a service).
1902 * @param section a section in the configuration file
1903 * @return #GNUNET_OK (continue)
1906 setup_service (void *cls,
1907 const char *section)
1909 struct ServiceList *sl;
1913 struct sockaddr **addrs;
1914 socklen_t *addr_lens;
1917 if (0 == strcasecmp (section,
1921 GNUNET_CONFIGURATION_get_value_string (cfg,
1926 /* not a service section */
1930 GNUNET_CONFIGURATION_have_value (cfg,
1934 GNUNET_CONFIGURATION_get_value_yesno (cfg,
1938 if (GNUNET_NO == start_user)
1940 GNUNET_free (binary);
1941 return; /* user service, and we don't deal with those */
1946 if (GNUNET_NO == start_system)
1948 GNUNET_free (binary);
1949 return; /* system service, and we don't deal with those */
1952 sl = find_service (section);
1955 /* got the same section twice!? */
1957 GNUNET_free (binary);
1962 GNUNET_CONFIGURATION_get_value_filename (cfg,
1967 GNUNET_CONFIGURATION_get_value_filename (cfg,
1971 (0 != STAT (config, &sbuf)))
1975 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1978 GNUNET_free (config);
1982 sl = GNUNET_new (struct ServiceList);
1983 sl->name = GNUNET_strdup (section);
1984 sl->binary = binary;
1985 sl->config = config;
1986 sl->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
1987 sl->restart_at = GNUNET_TIME_UNIT_FOREVER_ABS;
1989 sl->pipe_control = GNUNET_YES;
1991 if (GNUNET_CONFIGURATION_have_value (cfg,
1994 sl->pipe_control = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1998 GNUNET_CONTAINER_DLL_insert (running_head,
2002 GNUNET_CONFIGURATION_get_value_yesno (cfg,
2006 sl->force_start = GNUNET_YES;
2008 GNUNET_CONFIGURATION_get_value_yesno (cfg,
2016 GNUNET_CONFIGURATION_get_value_yesno (cfg,
2021 if (0 >= (ret = get_server_addresses (section,
2026 /* this will free (or capture) addrs[i] */
2027 for (unsigned int i = 0; i < ret; i++)
2028 create_listen_socket (addrs[i],
2031 GNUNET_free (addrs);
2032 GNUNET_free (addr_lens);
2037 * A client connected, mark as a monitoring client.
2039 * @param cls closure
2040 * @param client identification of the client
2041 * @param mq queue to talk to @a client
2045 client_connect_cb (void *cls,
2046 struct GNUNET_SERVICE_Client *client,
2047 struct GNUNET_MQ_Handle *mq)
2049 /* All clients are considered to be of the "monitor" kind
2050 * (that is, they don't affect ARM shutdown).
2052 GNUNET_SERVICE_client_mark_monitor (client);
2058 * A client disconnected, clean up associated state.
2060 * @param cls closure
2061 * @param client identification of the client
2062 * @param app_ctx must match @a client
2065 client_disconnect_cb (void *cls,
2066 struct GNUNET_SERVICE_Client *client,
2069 struct ServiceList *sl;
2071 GNUNET_assert (client == app_ctx);
2073 for (sl = running_head; NULL != sl; sl = sl->next)
2074 if (sl->killing_client == client)
2075 sl->killing_client = NULL;
2080 * Handle MONITOR-message.
2082 * @param cls identification of the client
2083 * @param message the actual message
2084 * @return #GNUNET_OK to keep the connection open,
2085 * #GNUNET_SYSERR to close it (signal serious error)
2088 handle_monitor (void *cls,
2089 const struct GNUNET_MessageHeader *message)
2091 struct GNUNET_SERVICE_Client *client = cls;
2093 /* FIXME: might want to start by letting monitor know about
2094 services that are already running */
2095 /* Removal is handled by the server implementation, internally. */
2096 GNUNET_notification_context_add (notifier,
2097 GNUNET_SERVICE_client_get_mq (client));
2098 broadcast_status ("arm",
2099 GNUNET_ARM_SERVICE_MONITORING_STARTED,
2101 GNUNET_SERVICE_client_continue (client);
2106 * Process arm requests.
2108 * @param cls closure
2109 * @param serv the initialized service
2110 * @param c configuration to use
2114 const struct GNUNET_CONFIGURATION_Handle *c,
2115 struct GNUNET_SERVICE_Handle *serv)
2117 struct ServiceList *sl;
2121 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
2124 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
2125 GNUNET_DISK_pipe_handle (sigpipe,
2126 GNUNET_DISK_PIPE_END_READ),
2131 GNUNET_CONFIGURATION_get_value_filename (cfg,
2133 "RESOURCE_DIAGNOSTICS",
2136 wait_file = fopen (wait_filename,
2138 if (NULL == wait_file)
2140 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
2147 GNUNET_CONFIGURATION_get_value_string (cfg,
2151 prefix_command = GNUNET_strdup ("");
2153 prefix_command = GNUNET_CONFIGURATION_expand_dollar (cfg,
2156 GNUNET_CONFIGURATION_get_value_string (cfg,
2160 final_option = GNUNET_strdup ("");
2162 final_option = GNUNET_CONFIGURATION_expand_dollar (cfg,
2165 GNUNET_CONFIGURATION_get_value_yesno (cfg,
2169 GNUNET_break (GNUNET_YES == start_user);
2170 start_system = GNUNET_NO;
2173 GNUNET_CONFIGURATION_get_value_yesno (cfg,
2177 GNUNET_break (GNUNET_YES == start_system);
2178 start_user = GNUNET_NO;
2180 GNUNET_CONFIGURATION_iterate_sections (cfg,
2184 /* start default services... */
2185 for (sl = running_head; NULL != sl; sl = sl->next)
2186 if (GNUNET_YES == sl->force_start)
2190 notifier = GNUNET_notification_context_create (MAX_NOTIFY_QUEUE);
2195 * The main function for the arm service.
2197 * @param argc number of arguments from the command line
2198 * @param argv command line arguments
2199 * @return 0 ok, 1 on error
2206 struct GNUNET_SIGNAL_Context *shc_chld;
2207 struct GNUNET_MQ_MessageHandler handlers[] = {
2208 GNUNET_MQ_hd_var_size (start,
2209 GNUNET_MESSAGE_TYPE_ARM_START,
2210 struct GNUNET_ARM_Message,
2212 GNUNET_MQ_hd_var_size (stop,
2213 GNUNET_MESSAGE_TYPE_ARM_STOP,
2214 struct GNUNET_ARM_Message,
2216 GNUNET_MQ_hd_fixed_size (monitor,
2217 GNUNET_MESSAGE_TYPE_ARM_MONITOR,
2218 struct GNUNET_MessageHeader,
2220 GNUNET_MQ_hd_fixed_size (list,
2221 GNUNET_MESSAGE_TYPE_ARM_LIST,
2222 struct GNUNET_ARM_Message,
2224 GNUNET_MQ_hd_fixed_size (test,
2225 GNUNET_MESSAGE_TYPE_ARM_TEST,
2226 struct GNUNET_MessageHeader,
2228 GNUNET_MQ_handler_end ()
2231 sigpipe = GNUNET_DISK_pipe (GNUNET_NO,
2235 GNUNET_assert (NULL != sigpipe);
2237 GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD,
2238 &sighandler_child_death);
2239 ret = GNUNET_SERVICE_run_ (argc,
2242 GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN,
2245 &client_disconnect_cb,
2249 if (NULL != wait_file)
2254 if (NULL != wait_filename)
2256 GNUNET_free (wait_filename);
2257 wait_filename = NULL;
2260 GNUNET_SIGNAL_handler_uninstall (shc_chld);
2262 GNUNET_DISK_pipe_close (sigpipe);
2268 #if defined(LINUX) && defined(__GLIBC__)
2272 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
2274 void __attribute__ ((constructor)) GNUNET_ARM_memory_init ()
2276 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2277 mallopt (M_TOP_PAD, 1 * 1024);
2283 /* end of gnunet-service-arm.c */