2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011, 2015 GNUnet e.V.
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * @file arm/gnunet-service-arm.c
23 * @brief the automated restart manager service
24 * @author Christian Grothoff
27 #include "gnunet_util_lib.h"
28 #include "gnunet_arm_service.h"
29 #include "gnunet_protocols.h"
34 * Name of the file for writing resource utilization summaries to.
36 static char *wait_filename;
39 * Handle for the file for writing resource summaries.
41 static FILE *wait_file;
46 * How many messages do we queue up at most for optional
47 * notifications to a client? (this can cause notifications
48 * about outgoing messages to be dropped).
50 #define MAX_NOTIFY_QUEUE 1024
54 * List of our services.
60 * Record with information about a listen socket we have open.
62 struct ServiceListeningInfo
65 * This is a linked list.
67 struct ServiceListeningInfo *next;
70 * This is a linked list.
72 struct ServiceListeningInfo *prev;
75 * Address this socket is listening on.
77 struct sockaddr *service_addr;
80 * Service this listen socket is for.
82 struct ServiceList *sl;
85 * Number of bytes in 'service_addr'
87 socklen_t service_addr_len;
90 * Our listening socket.
92 struct GNUNET_NETWORK_Handle *listen_socket;
95 * Task doing the accepting.
97 struct GNUNET_SCHEDULER_Task *accept_task;
103 * List of our services.
108 * This is a doubly-linked list.
110 struct ServiceList *next;
113 * This is a doubly-linked list.
115 struct ServiceList *prev;
118 * Linked list of listen sockets associated with this service.
120 struct ServiceListeningInfo *listen_head;
123 * Linked list of listen sockets associated with this service.
125 struct ServiceListeningInfo *listen_tail;
128 * Name of the service.
133 * Name of the binary used.
138 * Name of the configuration file used.
143 * Client to notify upon kill completion (waitpid), NULL
144 * if we should simply restart the process.
146 struct GNUNET_SERVER_Client *killing_client;
149 * ID of the request that killed the service (for reporting back).
151 uint64_t killing_client_request_id;
154 * Process structure pointer of the child.
156 struct GNUNET_OS_Process *proc;
159 * Process exponential backoff time
161 struct GNUNET_TIME_Relative backoff;
164 * Absolute time at which the process is scheduled to restart in case of death
166 struct GNUNET_TIME_Absolute restart_at;
169 * Time we asked the service to shut down (used to calculate time it took
170 * the service to terminate).
172 struct GNUNET_TIME_Absolute killed_at;
175 * Is this service to be started by default (or did a client tell us explicitly
176 * to start it)? #GNUNET_NO if the service is started only upon 'accept' on a
177 * listen socket or possibly explicitly by a client changing the value.
182 * Should we use pipes to signal this process? (YES for Java binaries and if we
189 * List of running services.
191 static struct ServiceList *running_head;
194 * List of running services.
196 static struct ServiceList *running_tail;
201 static const struct GNUNET_CONFIGURATION_Handle *cfg;
204 * Command to prepend to each actual command.
206 static char *prefix_command;
209 * Option to append to each actual command.
211 static char *final_option;
214 * ID of task called whenever we get a SIGCHILD.
216 static struct GNUNET_SCHEDULER_Task *child_death_task;
219 * ID of task called whenever the timeout for restarting a child
222 static struct GNUNET_SCHEDULER_Task *child_restart_task;
225 * Pipe used to communicate shutdown via signal.
227 static struct GNUNET_DISK_PipeHandle *sigpipe;
230 * Are we in shutdown mode?
232 static int in_shutdown;
235 * Are we starting user services?
237 static int start_user = GNUNET_YES;
240 * Are we starting system services?
242 static int start_system = GNUNET_YES;
245 * Handle to our server instance. Our server is a bit special in that
246 * its service is not immediately stopped once we get a shutdown
247 * request (since we need to continue service until all of our child
248 * processes are dead). This handle is used to shut down the server
249 * (and thus trigger process termination) once all child processes are
250 * also dead. A special option in the ARM configuration modifies the
251 * behaviour of the service implementation to not do the shutdown
254 static struct GNUNET_SERVER_Handle *server;
257 * Context for notifications we need to send to our clients.
259 static struct GNUNET_SERVER_NotificationContext *notifier;
263 * Transmit a status result message.
265 * @param cls a `unit16_t *` with message type
266 * @param size number of bytes available in @a buf
267 * @param buf where to copy the message, NULL on error
268 * @return number of bytes copied to @a buf
271 write_result (void *cls, size_t size, void *buf)
273 struct GNUNET_ARM_ResultMessage *msg = cls;
278 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
279 _("Could not send status result to client\n"));
281 return 0; /* error, not much we can do */
283 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
284 "Sending status response %u to client\n",
285 (unsigned int) msg->result);
286 msize = msg->arm_msg.header.size;
287 GNUNET_assert (size >= msize);
288 msg->arm_msg.header.size = htons (msg->arm_msg.header.size);
289 msg->arm_msg.header.type = htons (msg->arm_msg.header.type);
290 msg->result = htonl (msg->result);
291 msg->arm_msg.request_id = GNUNET_htonll (msg->arm_msg.request_id);
292 memcpy (buf, msg, msize);
299 * Transmit the list of running services.
301 * @param cls pointer to `struct GNUNET_ARM_ListResultMessage` with the message
302 * @param size number of bytes available in @a buf
303 * @param buf where to copy the message, NULL on error
304 * @return number of bytes copied to @a buf
307 write_list_result (void *cls, size_t size, void *buf)
309 struct GNUNET_ARM_ListResultMessage *msg = cls;
314 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
315 _("Could not send list result to client\n"));
317 return 0; /* error, not much we can do */
320 rslt_size = msg->arm_msg.header.size;
321 GNUNET_assert (size >= rslt_size);
322 msg->arm_msg.header.size = htons (msg->arm_msg.header.size);
323 msg->arm_msg.header.type = htons (msg->arm_msg.header.type);
324 msg->arm_msg.request_id = GNUNET_htonll (msg->arm_msg.request_id);
325 msg->count = htons (msg->count);
327 memcpy (buf, msg, rslt_size);
334 * Signal our client that we will start or stop the
337 * @param client who is being signalled
338 * @param name name of the service
339 * @param request_id id of the request that is being responded to.
340 * @param result message type to send
341 * @return NULL if it was not found
344 signal_result (struct GNUNET_SERVER_Client *client,
347 enum GNUNET_ARM_Result result)
349 struct GNUNET_ARM_ResultMessage *msg;
352 msize = sizeof (struct GNUNET_ARM_ResultMessage);
353 msg = GNUNET_malloc (msize);
354 msg->arm_msg.header.size = msize;
355 msg->arm_msg.header.type = GNUNET_MESSAGE_TYPE_ARM_RESULT;
356 msg->result = result;
357 msg->arm_msg.request_id = request_id;
359 GNUNET_SERVER_notify_transmit_ready (client, msize,
360 GNUNET_TIME_UNIT_FOREVER_REL,
366 * Tell all clients about status change of a service.
368 * @param name name of the service
369 * @param status message type to send
370 * @param unicast if not NULL, send to this client only.
371 * otherwise, send to all clients in the notifier
374 broadcast_status (const char *name,
375 enum GNUNET_ARM_ServiceStatus status,
376 struct GNUNET_SERVER_Client *unicast)
378 struct GNUNET_ARM_StatusMessage *msg;
381 if (NULL == notifier)
383 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
384 "Sending status %u of service `%s' to client\n",
385 (unsigned int) status, name);
386 namelen = strlen (name);
387 msg = GNUNET_malloc (sizeof (struct GNUNET_ARM_StatusMessage) + namelen + 1);
388 msg->header.size = htons (sizeof (struct GNUNET_ARM_StatusMessage) + namelen + 1);
389 msg->header.type = htons (GNUNET_MESSAGE_TYPE_ARM_STATUS);
390 msg->status = htonl ((uint32_t) (status));
391 memcpy ((char *) &msg[1], name, namelen + 1);
394 GNUNET_SERVER_notification_context_broadcast (notifier,
395 (struct GNUNET_MessageHeader *) msg, GNUNET_YES);
397 GNUNET_SERVER_notification_context_unicast (notifier, unicast,
398 (const struct GNUNET_MessageHeader *) msg, GNUNET_NO);
404 * Actually start the process for the given service.
406 * @param sl identifies service to start
407 * @param client that asked to start the service (may be NULL)
408 * @param request_id id of the request in response to which the process is
409 * being started. 0 if starting was not requested.
412 start_process (struct ServiceList *sl,
413 struct GNUNET_SERVER_Client *client,
419 int is_simple_service;
420 struct ServiceListeningInfo *sli;
426 /* calculate listen socket list */
429 for (sli = sl->listen_head; NULL != sli; sli = sli->next)
431 GNUNET_array_append (lsocks, ls,
432 GNUNET_NETWORK_get_fd (sli->listen_socket));
433 if (sli->accept_task != NULL)
435 GNUNET_SCHEDULER_cancel (sli->accept_task);
436 sli->accept_task = NULL;
440 GNUNET_array_append (lsocks, ls, INVALID_SOCKET);
442 GNUNET_array_append (lsocks, ls, -1);
445 /* obtain configuration */
447 GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "PREFIX",
449 loprefix = GNUNET_strdup (prefix_command);
451 GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "OPTIONS",
456 options = GNUNET_strdup (final_option);
457 /* replace '{}' with service name */
458 while (NULL != (optpos = strstr (options, "{}")))
460 /* terminate string at opening parenthesis */
462 GNUNET_asprintf (&new_options, "%s%s%s", options, sl->name, optpos + 2);
463 GNUNET_free (options);
464 options = new_options;
466 options = GNUNET_CONFIGURATION_expand_dollar (cfg, options);
468 use_debug = GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name, "DEBUG");
471 const char *service_type = NULL;
472 const char *choices[] = { "GNUNET", "SIMPLE", NULL };
473 is_simple_service = GNUNET_NO;
475 GNUNET_CONFIGURATION_get_value_choice (cfg,
480 (0 == strcasecmp (service_type, "SIMPLE")) )
481 is_simple_service = GNUNET_YES;
484 GNUNET_assert (NULL == sl->proc);
485 if (GNUNET_YES == is_simple_service)
487 /* A simple service will receive no GNUnet specific
488 command line options. */
489 binary = GNUNET_strdup (sl->binary);
490 binary = GNUNET_CONFIGURATION_expand_dollar (cfg, binary);
491 GNUNET_asprintf ("edbinary,
494 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
495 "Starting simple service `%s' using binary `%s'\n",
496 sl->name, sl->binary);
497 /* FIXME: dollar expansion should only be done outside
498 * of ''-quoted strings, escaping should be considered. */
500 options = GNUNET_CONFIGURATION_expand_dollar (cfg, options);
502 GNUNET_OS_start_process_s (sl->pipe_control,
503 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
504 lsocks, loprefix, quotedbinary,
509 /* actually start process */
510 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
511 "Starting service `%s' using binary `%s' and configuration `%s'\n",
512 sl->name, sl->binary, sl->config);
513 binary = GNUNET_OS_get_libexec_binary_path (sl->binary);
514 GNUNET_asprintf ("edbinary,
518 if (GNUNET_YES == use_debug)
520 if (NULL == sl->config)
522 GNUNET_OS_start_process_s (sl->pipe_control,
523 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
524 lsocks, loprefix, quotedbinary, "-L",
525 "DEBUG", options, NULL);
528 GNUNET_OS_start_process_s (sl->pipe_control,
529 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
530 lsocks, loprefix, quotedbinary, "-c",
532 "DEBUG", options, NULL);
536 if (NULL == sl->config)
538 GNUNET_OS_start_process_s (sl->pipe_control,
539 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
540 lsocks, loprefix, quotedbinary,
544 GNUNET_OS_start_process_s (sl->pipe_control,
545 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
546 lsocks, loprefix, quotedbinary, "-c",
547 sl->config, options, NULL);
550 GNUNET_free (binary);
551 GNUNET_free (quotedbinary);
552 if (sl->proc == NULL)
554 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
555 _("Failed to start service `%s'\n"),
558 signal_result (client,
561 GNUNET_ARM_RESULT_START_FAILED);
565 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
566 _("Starting service `%s'\n"),
568 broadcast_status (sl->name, GNUNET_ARM_SERVICE_STARTING, NULL);
570 signal_result (client, sl->name, request_id, GNUNET_ARM_RESULT_STARTING);
573 GNUNET_free (loprefix);
574 GNUNET_free (options);
575 GNUNET_array_grow (lsocks, ls, 0);
580 * Find the process with the given service
581 * name in the given list and return it.
583 * @param name which service entry to look up
584 * @return NULL if it was not found
586 static struct ServiceList *
587 find_service (const char *name)
589 struct ServiceList *sl;
594 if (0 == strcasecmp (sl->name, name))
603 * First connection has come to the listening socket associated with the service,
604 * create the service in order to relay the incoming connection to it
606 * @param cls callback data, `struct ServiceListeningInfo` describing a listen socket
609 accept_connection (void *cls)
611 struct ServiceListeningInfo *sli = cls;
612 struct ServiceList *sl = sli->sl;
614 sli->accept_task = NULL;
615 GNUNET_assert (GNUNET_NO == in_shutdown);
616 start_process (sl, NULL, 0);
621 * Creating a listening socket for each of the service's addresses and
622 * wait for the first incoming connection to it
624 * @param sa address associated with the service
625 * @param addr_len length of @a sa
626 * @param sl service entry for the service in question
629 create_listen_socket (struct sockaddr *sa,
631 struct ServiceList *sl)
634 struct GNUNET_NETWORK_Handle *sock;
635 struct ServiceListeningInfo *sli;
641 switch (sa->sa_family)
644 sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
647 sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
650 if (strcmp (GNUNET_a2s (sa, addr_len), "@") == 0) /* Do not bind to blank UNIX path! */
652 sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
657 errno = EAFNOSUPPORT;
662 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
663 _("Unable to create socket for service `%s': %s\n"),
664 sl->name, STRERROR (errno));
668 if (GNUNET_NETWORK_socket_setsockopt
669 (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
670 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
673 if ((sa->sa_family == AF_INET6) &&
674 (GNUNET_NETWORK_socket_setsockopt
675 (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK))
676 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
680 if (AF_UNIX == sa->sa_family)
681 GNUNET_NETWORK_unix_precheck ((struct sockaddr_un *) sa);
684 GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) sa, addr_len))
686 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
687 _("Unable to bind listening socket for service `%s' to address `%s': %s\n"),
689 GNUNET_a2s (sa, addr_len),
691 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
696 if ((AF_UNIX == sa->sa_family)
698 /* Permission settings are not required when abstract sockets are used */
699 && ('\0' != ((const struct sockaddr_un *)sa)->sun_path[0])
704 GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name,
707 GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name,
709 GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sa)->sun_path,
715 if (GNUNET_NETWORK_socket_listen (sock, 5) != GNUNET_OK)
717 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
718 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
722 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
723 _("ARM now monitors connections to service `%s' at `%s'\n"),
724 sl->name, GNUNET_a2s (sa, addr_len));
725 sli = GNUNET_new (struct ServiceListeningInfo);
726 sli->service_addr = sa;
727 sli->service_addr_len = addr_len;
728 sli->listen_socket = sock;
731 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sock,
732 &accept_connection, sli);
733 GNUNET_CONTAINER_DLL_insert (sl->listen_head,
740 * Remove and free an entry in the service list. Listen sockets
741 * must have already been cleaned up. Only to be called during shutdown.
743 * @param sl entry to free
746 free_service (struct ServiceList *sl)
748 GNUNET_assert (GNUNET_YES == in_shutdown);
749 GNUNET_CONTAINER_DLL_remove (running_head, running_tail, sl);
750 GNUNET_assert (NULL == sl->listen_head);
751 GNUNET_free_non_null (sl->config);
752 GNUNET_free_non_null (sl->binary);
753 GNUNET_free (sl->name);
759 * Handle START-message.
761 * @param cls closure (always NULL)
762 * @param client identification of the client
763 * @param message the actual message
764 * @return #GNUNET_OK to keep the connection open,
765 * #GNUNET_SYSERR to close it (signal serious error)
768 handle_start (void *cls,
769 struct GNUNET_SERVER_Client *client,
770 const struct GNUNET_MessageHeader *message)
772 const char *servicename;
773 struct ServiceList *sl;
776 struct GNUNET_ARM_Message *amsg;
778 amsg = (struct GNUNET_ARM_Message *) message;
779 request_id = GNUNET_ntohll (amsg->request_id);
780 size = ntohs (amsg->header.size);
781 size -= sizeof (struct GNUNET_ARM_Message);
782 servicename = (const char *) &amsg[1];
783 if ((size == 0) || (servicename[size - 1] != '\0'))
786 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
789 if (GNUNET_YES == in_shutdown)
791 signal_result (client, servicename, request_id,
792 GNUNET_ARM_RESULT_IN_SHUTDOWN);
793 GNUNET_SERVER_receive_done (client, GNUNET_OK);
796 sl = find_service (servicename);
799 signal_result (client, servicename, request_id,
800 GNUNET_ARM_RESULT_IS_NOT_KNOWN);
801 GNUNET_SERVER_receive_done (client, GNUNET_OK);
804 sl->force_start = GNUNET_YES;
805 if (NULL != sl->proc)
807 signal_result (client, servicename, request_id,
808 GNUNET_ARM_RESULT_IS_STARTED_ALREADY);
809 GNUNET_SERVER_receive_done (client, GNUNET_OK);
812 start_process (sl, client, request_id);
813 GNUNET_SERVER_receive_done (client, GNUNET_OK);
818 * Start a shutdown sequence.
820 * @param cls closure (refers to service)
823 trigger_shutdown (void *cls)
825 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
826 "Triggering shutdown\n");
827 GNUNET_SCHEDULER_shutdown ();
832 * Handle STOP-message.
834 * @param cls closure (always NULL)
835 * @param client identification of the client
836 * @param message the actual message
837 * @return #GNUNET_OK to keep the connection open,
838 * #GNUNET_SYSERR to close it (signal serious error)
841 handle_stop (void *cls,
842 struct GNUNET_SERVER_Client *client,
843 const struct GNUNET_MessageHeader *message)
845 struct ServiceList *sl;
846 const char *servicename;
849 struct GNUNET_ARM_Message *amsg;
851 amsg = (struct GNUNET_ARM_Message *) message;
852 request_id = GNUNET_ntohll (amsg->request_id);
853 size = ntohs (amsg->header.size);
854 size -= sizeof (struct GNUNET_ARM_Message);
855 servicename = (const char *) &amsg[1];
856 if ((size == 0) || (servicename[size - 1] != '\0'))
859 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
862 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
863 _("Preparing to stop `%s'\n"),
865 if (0 == strcasecmp (servicename, "arm"))
867 broadcast_status (servicename,
868 GNUNET_ARM_SERVICE_STOPPING, NULL);
869 signal_result (client,
872 GNUNET_ARM_RESULT_STOPPING);
873 GNUNET_SERVER_client_persist_ (client);
874 GNUNET_SCHEDULER_add_now (&trigger_shutdown, NULL);
875 GNUNET_SERVER_receive_done (client, GNUNET_OK);
878 sl = find_service (servicename);
881 signal_result (client,
884 GNUNET_ARM_RESULT_IS_NOT_KNOWN);
885 GNUNET_SERVER_receive_done (client, GNUNET_OK);
888 sl->force_start = GNUNET_NO;
889 if (GNUNET_YES == in_shutdown)
891 /* shutdown in progress */
892 signal_result (client,
895 GNUNET_ARM_RESULT_IN_SHUTDOWN);
896 GNUNET_SERVER_receive_done (client, GNUNET_OK);
899 if (NULL != sl->killing_client)
901 /* killing already in progress */
902 signal_result (client,
905 GNUNET_ARM_RESULT_IS_STOPPING_ALREADY);
906 GNUNET_SERVER_receive_done (client, GNUNET_OK);
909 if (NULL == sl->proc)
911 /* process is down */
912 signal_result (client,
915 GNUNET_ARM_RESULT_IS_STOPPED_ALREADY);
916 GNUNET_SERVER_receive_done (client, GNUNET_OK);
919 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
920 "Sending kill signal to service `%s', waiting for process to die.\n",
922 broadcast_status (servicename,
923 GNUNET_ARM_SERVICE_STOPPING,
925 /* no signal_start - only when it's STOPPED */
926 sl->killed_at = GNUNET_TIME_absolute_get ();
927 if (0 != GNUNET_OS_process_kill (sl->proc, GNUNET_TERM_SIG))
928 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
929 sl->killing_client = client;
930 sl->killing_client_request_id = request_id;
931 GNUNET_SERVER_client_keep (client);
932 GNUNET_SERVER_receive_done (client, GNUNET_OK);
937 * Handle LIST-message.
939 * @param cls closure (always NULL)
940 * @param client identification of the client
941 * @param message the actual message
944 handle_list (void *cls, struct GNUNET_SERVER_Client *client,
945 const struct GNUNET_MessageHeader *message)
947 struct GNUNET_ARM_ListResultMessage *msg;
948 struct GNUNET_ARM_Message *request;
949 size_t string_list_size;
951 struct ServiceList *sl;
957 request = (struct GNUNET_ARM_Message *) message;
958 GNUNET_break (0 == ntohl (request->reserved));
960 string_list_size = 0;
961 /* first count the running processes get their name's size */
962 for (sl = running_head; NULL != sl; sl = sl->next)
964 if (NULL != sl->proc)
966 string_list_size += strlen (sl->name);
967 string_list_size += strlen (sl->binary);
968 string_list_size += 4;
973 total_size = sizeof (struct GNUNET_ARM_ListResultMessage)
975 msg = GNUNET_malloc (total_size);
976 msg->arm_msg.header.size = total_size;
977 msg->arm_msg.header.type = GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT;
978 msg->arm_msg.reserved = htonl (0);
979 msg->arm_msg.request_id = GNUNET_ntohll (request->request_id);
982 char *pos = (char *)&msg[1];
983 for (sl = running_head; NULL != sl; sl = sl->next)
985 if (NULL != sl->proc)
987 size_t s = strlen (sl->name) + strlen (sl->binary) + 4;
988 GNUNET_snprintf (pos, s, "%s (%s)", sl->name, sl->binary);
992 GNUNET_SERVER_notify_transmit_ready (client,
994 GNUNET_TIME_UNIT_FOREVER_REL,
995 &write_list_result, msg);
996 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1001 * We are done with everything. Stop remaining
1002 * tasks, signal handler and the server.
1007 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Last shutdown phase\n");
1008 if (NULL != notifier)
1010 GNUNET_SERVER_notification_context_destroy (notifier);
1015 GNUNET_SERVER_destroy (server);
1018 if (NULL != child_death_task)
1020 GNUNET_SCHEDULER_cancel (child_death_task);
1021 child_death_task = NULL;
1027 * Count how many services are still active.
1029 * @param running_head list of services
1030 * @return number of active services found
1033 list_count (struct ServiceList *running_head)
1035 struct ServiceList *i;
1036 unsigned int res = 0;
1038 for (res = 0, i = running_head; i; i = i->next, res++)
1039 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1047 * Task run for shutdown.
1049 * @param cls closure, NULL if we need to self-restart
1052 shutdown_task (void *cls)
1054 struct ServiceList *pos;
1055 struct ServiceList *nxt;
1056 struct ServiceListeningInfo *sli;
1058 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1059 "First shutdown phase\n");
1060 if (NULL != child_restart_task)
1062 GNUNET_SCHEDULER_cancel (child_restart_task);
1063 child_restart_task = NULL;
1065 in_shutdown = GNUNET_YES;
1066 /* first, stop listening */
1067 for (pos = running_head; NULL != pos; pos = pos->next)
1069 while (NULL != (sli = pos->listen_head))
1071 GNUNET_CONTAINER_DLL_remove (pos->listen_head,
1074 if (NULL != sli->accept_task)
1076 GNUNET_SCHEDULER_cancel (sli->accept_task);
1077 sli->accept_task = NULL;
1079 GNUNET_break (GNUNET_OK ==
1080 GNUNET_NETWORK_socket_close (sli->listen_socket));
1081 GNUNET_free (sli->service_addr);
1085 /* then, shutdown all existing service processes */
1087 while (NULL != (pos = nxt))
1090 if (NULL != pos->proc)
1092 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1093 "Stopping service `%s'\n",
1095 pos->killed_at = GNUNET_TIME_absolute_get ();
1096 if (0 != GNUNET_OS_process_kill (pos->proc, GNUNET_TERM_SIG))
1097 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
1104 /* finally, should all service processes be already gone, terminate for real */
1105 if (NULL == running_head)
1108 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1109 "Delaying shutdown, have %u childs still running\n",
1110 list_count (running_head));
1115 * Task run whenever it is time to restart a child that died.
1117 * @param cls closure, always NULL
1120 delayed_restart_task (void *cls)
1123 struct ServiceList *sl;
1124 struct GNUNET_TIME_Relative lowestRestartDelay;
1125 struct ServiceListeningInfo *sli;
1127 child_restart_task = NULL;
1128 GNUNET_assert (GNUNET_NO == in_shutdown);
1129 lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL;
1131 /* check for services that need to be restarted due to
1132 * configuration changes or because the last restart failed */
1133 for (sl = running_head; NULL != sl; sl = sl->next)
1135 if (NULL != sl->proc)
1137 /* service is currently not running */
1138 if (0 == GNUNET_TIME_absolute_get_remaining (sl->restart_at).rel_value_us)
1140 /* restart is now allowed */
1141 if (sl->force_start)
1143 /* process should run by default, start immediately */
1144 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1145 _("Restarting service `%s'.\n"),
1147 start_process (sl, NULL, 0);
1151 /* process is run on-demand, ensure it is re-started if there is demand */
1152 for (sli = sl->listen_head; NULL != sli; sli = sli->next)
1153 if (NULL == sli->accept_task)
1155 /* accept was actually paused, so start it again */
1157 GNUNET_SCHEDULER_add_read_net
1158 (GNUNET_TIME_UNIT_FOREVER_REL,
1160 &accept_connection, sli);
1166 /* update calculation for earliest time to reactivate a service */
1167 lowestRestartDelay =
1168 GNUNET_TIME_relative_min (lowestRestartDelay,
1169 GNUNET_TIME_absolute_get_remaining
1173 if (lowestRestartDelay.rel_value_us != GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1175 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1176 "Will restart process in %s\n",
1177 GNUNET_STRINGS_relative_time_to_string (lowestRestartDelay, GNUNET_YES));
1178 child_restart_task =
1179 GNUNET_SCHEDULER_add_delayed_with_priority (lowestRestartDelay,
1180 GNUNET_SCHEDULER_PRIORITY_IDLE,
1181 &delayed_restart_task, NULL);
1187 * Task triggered whenever we receive a SIGCHLD (child
1190 * @param cls closure, NULL if we need to self-restart
1193 maint_child_death (void *cls)
1195 struct ServiceList *pos;
1196 struct ServiceList *next;
1197 struct ServiceListeningInfo *sli;
1198 const char *statstr;
1202 enum GNUNET_OS_ProcessStatusType statusType;
1203 unsigned long statusCode;
1204 const struct GNUNET_DISK_FileHandle *pr;
1206 pr = GNUNET_DISK_pipe_handle (sigpipe,
1207 GNUNET_DISK_PIPE_END_READ);
1208 child_death_task = NULL;
1209 /* consume the signal */
1210 GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
1212 /* check for services that died (WAITPID) */
1213 next = running_head;
1214 while (NULL != (pos = next))
1218 if (NULL == pos->proc)
1220 if (GNUNET_YES == in_shutdown)
1225 if (NULL != wait_file)
1227 /* need to use 'wait4()' to obtain and log performance data */
1232 pid = GNUNET_OS_process_get_pid (pos->proc);
1238 continue; /* no process done */
1239 if (WIFEXITED (status))
1241 statusType = GNUNET_OS_PROCESS_EXITED;
1242 statusCode = WEXITSTATUS (status);
1244 else if (WIFSIGNALED (status))
1246 statusType = GNUNET_OS_PROCESS_SIGNALED;
1247 statusCode = WTERMSIG (status);
1249 else if (WIFSTOPPED (status))
1251 statusType = GNUNET_OS_PROCESS_SIGNALED;
1252 statusCode = WSTOPSIG (status);
1255 else if (WIFCONTINUED (status))
1257 statusType = GNUNET_OS_PROCESS_RUNNING;
1263 statusType = GNUNET_OS_PROCESS_UNKNOWN;
1266 if ( (GNUNET_OS_PROCESS_EXITED == statusType) ||
1267 (GNUNET_OS_PROCESS_SIGNALED == statusType) )
1269 double utime = ru.ru_utime.tv_sec + (ru.ru_utime.tv_usec / 10e6);
1270 double stime = ru.ru_stime.tv_sec + (ru.ru_stime.tv_usec / 10e6);
1272 "%s(%u) %.3f %.3f %llu %llu %llu %llu %llu\n",
1277 (unsigned long long) ru.ru_maxrss,
1278 (unsigned long long) ru.ru_inblock,
1279 (unsigned long long) ru.ru_oublock,
1280 (unsigned long long) ru.ru_nvcsw,
1281 (unsigned long long) ru.ru_nivcsw);
1284 else /* continue with JUST this "if" as "else" (intentionally no brackets!) */
1286 if ( (GNUNET_SYSERR ==
1288 GNUNET_OS_process_status (pos->proc,
1291 (ret == GNUNET_NO) ||
1292 (statusType == GNUNET_OS_PROCESS_STOPPED) ||
1293 (statusType == GNUNET_OS_PROCESS_UNKNOWN) ||
1294 (statusType == GNUNET_OS_PROCESS_RUNNING) )
1297 if (statusType == GNUNET_OS_PROCESS_EXITED)
1299 statstr = _( /* process termination method */ "exit");
1300 statcode = statusCode;
1302 else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
1304 statstr = _( /* process termination method */ "signal");
1305 statcode = statusCode;
1309 statstr = _( /* process termination method */ "unknown");
1312 if (0 != pos->killed_at.abs_value_us)
1314 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1315 _("Service `%s' took %s to terminate\n"),
1317 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->killed_at),
1320 GNUNET_OS_process_destroy (pos->proc);
1322 broadcast_status (pos->name,
1323 GNUNET_ARM_SERVICE_STOPPED,
1325 if (NULL != pos->killing_client)
1327 signal_result (pos->killing_client, pos->name,
1328 pos->killing_client_request_id,
1329 GNUNET_ARM_RESULT_STOPPED);
1330 GNUNET_SERVER_client_drop (pos->killing_client);
1331 pos->killing_client = NULL;
1332 pos->killing_client_request_id = 0;
1334 if (GNUNET_YES != in_shutdown)
1336 if ( (statusType == GNUNET_OS_PROCESS_EXITED) &&
1339 /* process terminated normally, allow restart at any time */
1340 pos->restart_at.abs_value_us = 0;
1341 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1342 _("Service `%s' terminated normally, will restart at any time\n"),
1344 /* process can still be re-started on-demand, ensure it is re-started if there is demand */
1345 for (sli = pos->listen_head; NULL != sli; sli = sli->next)
1347 GNUNET_break (NULL == sli->accept_task);
1349 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1357 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1358 _("Service `%s' terminated with status %s/%d, will restart in %s\n"),
1362 GNUNET_STRINGS_relative_time_to_string (pos->backoff,
1364 /* schedule restart */
1365 pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff);
1366 pos->backoff = GNUNET_TIME_STD_BACKOFF (pos->backoff);
1367 if (NULL != child_restart_task)
1368 GNUNET_SCHEDULER_cancel (child_restart_task);
1370 = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
1371 &delayed_restart_task,
1380 child_death_task = GNUNET_SCHEDULER_add_read_file (
1381 GNUNET_TIME_UNIT_FOREVER_REL,
1383 &maint_child_death, NULL);
1384 if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
1386 else if (GNUNET_YES == in_shutdown)
1387 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1388 "Delaying shutdown after child's death, still have %u children\n",
1389 list_count (running_head));
1395 * Signal handler called for SIGCHLD. Triggers the
1396 * respective handler by writing to the trigger pipe.
1399 sighandler_child_death ()
1402 int old_errno = errno; /* back-up errno */
1405 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
1406 (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
1408 errno = old_errno; /* restore errno */
1413 * Setup our service record for the given section in the configuration file
1414 * (assuming the section is for a service).
1417 * @param section a section in the configuration file
1418 * @return #GNUNET_OK (continue)
1421 setup_service (void *cls,
1422 const char *section)
1424 struct ServiceList *sl;
1428 struct sockaddr **addrs;
1429 socklen_t *addr_lens;
1433 if (strcasecmp (section, "arm") == 0)
1436 GNUNET_CONFIGURATION_get_value_string (cfg, section, "BINARY", &binary))
1438 /* not a service section */
1442 GNUNET_CONFIGURATION_have_value (cfg, section, "USER_SERVICE")) &&
1444 GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "USER_SERVICE")))
1446 if (GNUNET_NO == start_user)
1448 GNUNET_free (binary);
1449 return; /* user service, and we don't deal with those */
1454 if (GNUNET_NO == start_system)
1456 GNUNET_free (binary);
1457 return; /* system service, and we don't deal with those */
1460 sl = find_service (section);
1463 /* got the same section twice!? */
1465 GNUNET_free (binary);
1470 GNUNET_CONFIGURATION_get_value_filename (cfg, section,
1474 GNUNET_CONFIGURATION_get_value_filename (cfg,
1478 (0 != STAT (config, &sbuf)))
1482 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1485 GNUNET_free (config);
1489 sl = GNUNET_new (struct ServiceList);
1490 sl->name = GNUNET_strdup (section);
1491 sl->binary = binary;
1492 sl->config = config;
1493 sl->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
1494 sl->restart_at = GNUNET_TIME_UNIT_FOREVER_ABS;
1496 sl->pipe_control = GNUNET_YES;
1498 if (GNUNET_CONFIGURATION_have_value (cfg, section, "PIPECONTROL"))
1499 sl->pipe_control = GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "PIPECONTROL");
1501 GNUNET_CONTAINER_DLL_insert (running_head,
1505 GNUNET_CONFIGURATION_get_value_yesno (cfg,
1509 sl->force_start = GNUNET_YES;
1511 GNUNET_CONFIGURATION_get_value_yesno (cfg,
1519 GNUNET_CONFIGURATION_get_value_yesno (cfg,
1524 if (0 >= (ret = GNUNET_SERVICE_get_server_addresses (section,
1529 /* this will free (or capture) addrs[i] */
1530 for (i = 0; i < ret; i++)
1531 create_listen_socket (addrs[i],
1534 GNUNET_free (addrs);
1535 GNUNET_free (addr_lens);
1540 * A client connected, add it to the notification context.
1542 * @param cls closure
1543 * @param client identification of the client
1546 handle_client_connecting (void *cls, struct GNUNET_SERVER_Client *client)
1548 /* All clients are considered to be of the "monitor" kind
1549 * (that is, they don't affect ARM shutdown).
1552 GNUNET_SERVER_client_mark_monitor (client);
1557 * Handle MONITOR-message.
1559 * @param cls closure (always NULL)
1560 * @param client identification of the client
1561 * @param message the actual message
1562 * @return #GNUNET_OK to keep the connection open,
1563 * #GNUNET_SYSERR to close it (signal serious error)
1566 handle_monitor (void *cls, struct GNUNET_SERVER_Client *client,
1567 const struct GNUNET_MessageHeader *message)
1569 /* Removal is handled by the server implementation, internally. */
1570 if ((NULL != client) && (NULL != notifier))
1572 GNUNET_SERVER_notification_context_add (notifier, client);
1573 broadcast_status ("arm", GNUNET_ARM_SERVICE_MONITORING_STARTED, client);
1574 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1580 * Process arm requests.
1582 * @param cls closure
1583 * @param serv the initialized server
1584 * @param c configuration to use
1587 run (void *cls, struct GNUNET_SERVER_Handle *serv,
1588 const struct GNUNET_CONFIGURATION_Handle *c)
1590 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1591 {&handle_start, NULL, GNUNET_MESSAGE_TYPE_ARM_START, 0},
1592 {&handle_stop, NULL, GNUNET_MESSAGE_TYPE_ARM_STOP, 0},
1593 {&handle_monitor, NULL, GNUNET_MESSAGE_TYPE_ARM_MONITOR,
1594 sizeof (struct GNUNET_MessageHeader)},
1595 {&handle_list, NULL, GNUNET_MESSAGE_TYPE_ARM_LIST,
1596 sizeof (struct GNUNET_ARM_Message)},
1599 struct ServiceList *sl;
1603 GNUNET_assert (NULL != serv);
1604 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1607 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1608 GNUNET_DISK_pipe_handle (sigpipe,
1609 GNUNET_DISK_PIPE_END_READ),
1610 &maint_child_death, NULL);
1613 GNUNET_CONFIGURATION_get_value_filename (cfg,
1615 "RESOURCE_DIAGNOSTICS",
1618 wait_file = fopen (wait_filename,
1620 if (NULL == wait_file)
1622 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1629 GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "GLOBAL_PREFIX",
1631 prefix_command = GNUNET_strdup ("");
1633 GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "GLOBAL_POSTFIX",
1635 final_option = GNUNET_strdup ("");
1637 GNUNET_CONFIGURATION_get_value_yesno (cfg, "ARM", "USER_ONLY"))
1639 GNUNET_break (GNUNET_YES == start_user);
1640 start_system = GNUNET_NO;
1643 GNUNET_CONFIGURATION_get_value_yesno (cfg, "ARM", "SYSTEM_ONLY"))
1645 GNUNET_break (GNUNET_YES == start_system);
1646 start_user = GNUNET_NO;
1648 GNUNET_CONFIGURATION_iterate_sections (cfg, &setup_service, NULL);
1650 /* start default services... */
1651 for (sl = running_head; NULL != sl; sl = sl->next)
1652 if (GNUNET_YES == sl->force_start)
1653 start_process (sl, NULL, 0);
1655 = GNUNET_SERVER_notification_context_create (server,
1657 GNUNET_SERVER_connect_notify (server,
1658 &handle_client_connecting, NULL);
1659 /* process client requests */
1660 GNUNET_SERVER_add_handlers (server,
1666 * The main function for the arm service.
1668 * @param argc number of arguments from the command line
1669 * @param argv command line arguments
1670 * @return 0 ok, 1 on error
1673 main (int argc, char *const *argv)
1676 struct GNUNET_SIGNAL_Context *shc_chld;
1678 sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
1679 GNUNET_assert (sigpipe != NULL);
1681 GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
1684 GNUNET_SERVICE_run (argc, argv, "arm",
1685 GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN, &run, NULL)) ? 0 : 1;
1687 if (NULL != wait_file)
1692 if (NULL != wait_filename)
1694 GNUNET_free (wait_filename);
1695 wait_filename = NULL;
1698 GNUNET_SIGNAL_handler_uninstall (shc_chld);
1700 GNUNET_DISK_pipe_close (sigpipe);
1706 #if defined(LINUX) && defined(__GLIBC__)
1710 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1712 void __attribute__ ((constructor)) GNUNET_ARM_memory_init ()
1714 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1715 mallopt (M_TOP_PAD, 1 * 1024);
1721 /* end of gnunet-service-arm.c */