-rps doxygen
[oweals/gnunet.git] / src / arm / gnunet-service-arm.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2010, 2011, 2015 GNUnet e.V.
4
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.
9
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.
14
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.
19 */
20
21 /**
22  * @file arm/gnunet-service-arm.c
23  * @brief the automated restart manager service
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_arm_service.h"
29 #include "gnunet_protocols.h"
30 #include "arm.h"
31
32 #if HAVE_WAIT4
33 /**
34  * Name of the file for writing resource utilization summaries to.
35  */
36 static char *wait_filename;
37
38 /**
39  * Handle for the file for writing resource summaries.
40  */
41 static FILE *wait_file;
42 #endif
43
44
45 /**
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).
49  */
50 #define MAX_NOTIFY_QUEUE 1024
51
52
53 /**
54  * List of our services.
55  */
56 struct ServiceList;
57
58
59 /**
60  * Record with information about a listen socket we have open.
61  */
62 struct ServiceListeningInfo
63 {
64   /**
65    * This is a linked list.
66    */
67   struct ServiceListeningInfo *next;
68
69   /**
70    * This is a linked list.
71    */
72   struct ServiceListeningInfo *prev;
73
74   /**
75    * Address this socket is listening on.
76    */
77   struct sockaddr *service_addr;
78
79   /**
80    * Service this listen socket is for.
81    */
82   struct ServiceList *sl;
83
84   /**
85    * Number of bytes in 'service_addr'
86    */
87   socklen_t service_addr_len;
88
89   /**
90    * Our listening socket.
91    */
92   struct GNUNET_NETWORK_Handle *listen_socket;
93
94   /**
95    * Task doing the accepting.
96    */
97   struct GNUNET_SCHEDULER_Task *accept_task;
98
99 };
100
101
102 /**
103  * List of our services.
104  */
105 struct ServiceList
106 {
107   /**
108    * This is a doubly-linked list.
109    */
110   struct ServiceList *next;
111
112   /**
113    * This is a doubly-linked list.
114    */
115   struct ServiceList *prev;
116
117   /**
118    * Linked list of listen sockets associated with this service.
119    */
120   struct ServiceListeningInfo *listen_head;
121
122   /**
123    * Linked list of listen sockets associated with this service.
124    */
125   struct ServiceListeningInfo *listen_tail;
126
127   /**
128    * Name of the service.
129    */
130   char *name;
131
132   /**
133    * Name of the binary used.
134    */
135   char *binary;
136
137   /**
138    * Name of the configuration file used.
139    */
140   char *config;
141
142   /**
143    * Client to notify upon kill completion (waitpid), NULL
144    * if we should simply restart the process.
145    */
146   struct GNUNET_SERVER_Client *killing_client;
147
148   /**
149    * ID of the request that killed the service (for reporting back).
150    */
151   uint64_t killing_client_request_id;
152
153   /**
154    * Process structure pointer of the child.
155    */
156   struct GNUNET_OS_Process *proc;
157
158   /**
159    * Process exponential backoff time
160    */
161   struct GNUNET_TIME_Relative backoff;
162
163   /**
164    * Absolute time at which the process is scheduled to restart in case of death
165    */
166   struct GNUNET_TIME_Absolute restart_at;
167
168   /**
169    * Time we asked the service to shut down (used to calculate time it took
170    * the service to terminate).
171    */
172   struct GNUNET_TIME_Absolute killed_at;
173
174   /**
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.
178    */
179   int force_start;
180
181   /**
182    * Should we use pipes to signal this process? (YES for Java binaries and if we
183    * are on Windoze).
184    */
185   int pipe_control;
186 };
187
188 /**
189  * List of running services.
190  */
191 static struct ServiceList *running_head;
192
193 /**
194  * List of running services.
195  */
196 static struct ServiceList *running_tail;
197
198 /**
199  * Our configuration
200  */
201 static const struct GNUNET_CONFIGURATION_Handle *cfg;
202
203 /**
204  * Command to prepend to each actual command.
205  */
206 static char *prefix_command;
207
208 /**
209  * Option to append to each actual command.
210  */
211 static char *final_option;
212
213 /**
214  * ID of task called whenever we get a SIGCHILD.
215  */
216 static struct GNUNET_SCHEDULER_Task *child_death_task;
217
218 /**
219  * ID of task called whenever the timeout for restarting a child
220  * expires.
221  */
222 static struct GNUNET_SCHEDULER_Task *child_restart_task;
223
224 /**
225  * Pipe used to communicate shutdown via signal.
226  */
227 static struct GNUNET_DISK_PipeHandle *sigpipe;
228
229 /**
230  * Are we in shutdown mode?
231  */
232 static int in_shutdown;
233
234 /**
235  * Are we starting user services?
236  */
237 static int start_user = GNUNET_YES;
238
239 /**
240  * Are we starting system services?
241  */
242 static int start_system = GNUNET_YES;
243
244 /**
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
252  * immediately.
253  */
254 static struct GNUNET_SERVER_Handle *server;
255
256 /**
257  * Context for notifications we need to send to our clients.
258  */
259 static struct GNUNET_SERVER_NotificationContext *notifier;
260
261
262 /**
263  * Transmit a status result message.
264  *
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
269  */
270 static size_t
271 write_result (void *cls, size_t size, void *buf)
272 {
273   struct GNUNET_ARM_ResultMessage *msg = cls;
274   size_t msize;
275
276   if (NULL == buf)
277   {
278     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
279                 _("Could not send status result to client\n"));
280     GNUNET_free (msg);
281     return 0;                   /* error, not much we can do */
282   }
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   GNUNET_memcpy (buf, msg, msize);
293   GNUNET_free (msg);
294   return msize;
295 }
296
297
298 /**
299  * Transmit the list of running services.
300  *
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
305  */
306 static size_t
307 write_list_result (void *cls, size_t size, void *buf)
308 {
309   struct GNUNET_ARM_ListResultMessage *msg = cls;
310   size_t rslt_size;
311
312   if (NULL == buf)
313   {
314     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
315                 _("Could not send list result to client\n"));
316     GNUNET_free (msg);
317     return 0;                   /* error, not much we can do */
318   }
319
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);
326
327   GNUNET_memcpy (buf, msg, rslt_size);
328   GNUNET_free (msg);
329   return rslt_size;
330 }
331
332
333 /**
334  * Signal our client that we will start or stop the
335  * service.
336  *
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
342  */
343 static void
344 signal_result (struct GNUNET_SERVER_Client *client,
345                const char *name,
346                uint64_t request_id,
347                enum GNUNET_ARM_Result result)
348 {
349   struct GNUNET_ARM_ResultMessage *msg;
350   size_t msize;
351
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;
358
359   GNUNET_SERVER_notify_transmit_ready (client, msize,
360                                        GNUNET_TIME_UNIT_FOREVER_REL,
361                                        write_result, msg);
362 }
363
364
365 /**
366  * Tell all clients about status change of a service.
367  *
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
372  */
373 static void
374 broadcast_status (const char *name,
375                   enum GNUNET_ARM_ServiceStatus status,
376                   struct GNUNET_SERVER_Client *unicast)
377 {
378   struct GNUNET_ARM_StatusMessage *msg;
379   size_t namelen;
380
381   if (NULL == notifier)
382     return;
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   GNUNET_memcpy ((char *) &msg[1], name, namelen + 1);
392
393   if (NULL == unicast)
394     GNUNET_SERVER_notification_context_broadcast (notifier,
395         (struct GNUNET_MessageHeader *) msg, GNUNET_YES);
396   else
397     GNUNET_SERVER_notification_context_unicast (notifier, unicast,
398         (const struct GNUNET_MessageHeader *) msg, GNUNET_NO);
399   GNUNET_free (msg);
400 }
401
402
403 /**
404  * Actually start the process for the given service.
405  *
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.
410  */
411 static void
412 start_process (struct ServiceList *sl,
413                struct GNUNET_SERVER_Client *client,
414                uint64_t request_id)
415 {
416   char *loprefix;
417   char *options;
418   int use_debug;
419   int is_simple_service;
420   struct ServiceListeningInfo *sli;
421   SOCKTYPE *lsocks;
422   unsigned int ls;
423   char *binary;
424   char *quotedbinary;
425
426   /* calculate listen socket list */
427   lsocks = NULL;
428   ls = 0;
429   for (sli = sl->listen_head; NULL != sli; sli = sli->next)
430     {
431       GNUNET_array_append (lsocks, ls,
432                            GNUNET_NETWORK_get_fd (sli->listen_socket));
433       if (sli->accept_task != NULL)
434         {
435           GNUNET_SCHEDULER_cancel (sli->accept_task);
436           sli->accept_task = NULL;
437         }
438     }
439 #if WINDOWS
440   GNUNET_array_append (lsocks, ls, INVALID_SOCKET);
441 #else
442   GNUNET_array_append (lsocks, ls, -1);
443 #endif
444
445   /* obtain configuration */
446   if (GNUNET_OK !=
447       GNUNET_CONFIGURATION_get_value_string (cfg,
448                                              sl->name,
449                                              "PREFIX",
450                                              &loprefix))
451     loprefix = GNUNET_strdup (prefix_command);
452   if (GNUNET_OK !=
453       GNUNET_CONFIGURATION_get_value_string (cfg,
454                                              sl->name,
455                                              "OPTIONS",
456                                              &options))
457     options = NULL;
458
459   {
460     char *new_options;
461     char *optpos;
462     char *fin_options;
463
464     fin_options = GNUNET_strdup (final_option);
465     /* replace '{}' with service name */
466     while (NULL != (optpos = strstr (fin_options, "{}")))
467     {
468       /* terminate string at opening parenthesis */
469       *optpos = 0;
470       GNUNET_asprintf (&new_options,
471                        "%s%s%s",
472                        fin_options,
473                        sl->name,
474                        optpos + 2);
475       GNUNET_free (fin_options);
476       fin_options = new_options;
477     }
478     if (NULL != options)
479     {
480       /* combine "fin_options" with "options" */
481       optpos = options;
482       GNUNET_asprintf (&options,
483                        "%s %s",
484                        fin_options,
485                        optpos);
486       GNUNET_free (optpos);
487     }
488     else
489     {
490       /* only have "fin_options", use that */
491       options = fin_options;
492     }
493   }
494   options = GNUNET_CONFIGURATION_expand_dollar (cfg,
495                                                 options);
496   use_debug = GNUNET_CONFIGURATION_get_value_yesno (cfg,
497                                                     sl->name,
498                                                     "DEBUG");
499   {
500     const char *service_type = NULL;
501     const char *choices[] = { "GNUNET", "SIMPLE", NULL };
502
503     is_simple_service = GNUNET_NO;
504     if ( (GNUNET_OK ==
505           GNUNET_CONFIGURATION_get_value_choice (cfg,
506                                                  sl->name,
507                                                  "TYPE",
508                                                  choices,
509                                                  &service_type)) &&
510          (0 == strcasecmp (service_type, "SIMPLE")) )
511       is_simple_service = GNUNET_YES;
512   }
513
514   GNUNET_assert (NULL == sl->proc);
515   if (GNUNET_YES == is_simple_service)
516   {
517     /* A simple service will receive no GNUnet specific
518        command line options. */
519     binary = GNUNET_strdup (sl->binary);
520     binary = GNUNET_CONFIGURATION_expand_dollar (cfg, binary);
521     GNUNET_asprintf (&quotedbinary,
522                      "\"%s\"",
523                      sl->binary);
524     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
525                 "Starting simple service `%s' using binary `%s'\n",
526                 sl->name, sl->binary);
527     /* FIXME: dollar expansion should only be done outside
528      * of ''-quoted strings, escaping should be considered. */
529     if (NULL != options)
530       options = GNUNET_CONFIGURATION_expand_dollar (cfg, options);
531     sl->proc =
532       GNUNET_OS_start_process_s (sl->pipe_control,
533                                  GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
534                                  lsocks,
535                                  loprefix,
536                                  quotedbinary,
537                                  options,
538                                  NULL);
539   }
540   else
541   {
542     /* actually start process */
543     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
544                 "Starting service `%s' using binary `%s' and configuration `%s'\n",
545                 sl->name, sl->binary, sl->config);
546     binary = GNUNET_OS_get_libexec_binary_path (sl->binary);
547     GNUNET_asprintf (&quotedbinary,
548                      "\"%s\"",
549                      binary);
550
551     if (GNUNET_YES == use_debug)
552     {
553       if (NULL == sl->config)
554         sl->proc =
555           GNUNET_OS_start_process_s (sl->pipe_control,
556                                      GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
557                                      lsocks,
558                                      loprefix,
559                                      quotedbinary,
560                                      "-L", "DEBUG",
561                                      options,
562                                      NULL);
563       else
564         sl->proc =
565             GNUNET_OS_start_process_s (sl->pipe_control,
566                                        GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
567                                        lsocks,
568                                        loprefix,
569                                        quotedbinary,
570                                        "-c", sl->config,
571                                        "-L", "DEBUG",
572                                        options,
573                                        NULL);
574     }
575     else
576     {
577       if (NULL == sl->config)
578         sl->proc =
579             GNUNET_OS_start_process_s (sl->pipe_control,
580                                        GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
581                                        lsocks,
582                                        loprefix,
583                                        quotedbinary,
584                                        options,
585                                        NULL);
586       else
587         sl->proc =
588             GNUNET_OS_start_process_s (sl->pipe_control,
589                                        GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
590                                        lsocks,
591                                        loprefix,
592                                        quotedbinary,
593                                        "-c", sl->config,
594                                        options,
595                                        NULL);
596     }
597   }
598   GNUNET_free (binary);
599   GNUNET_free (quotedbinary);
600   if (sl->proc == NULL)
601   {
602     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
603                 _("Failed to start service `%s'\n"),
604                 sl->name);
605     if (client)
606       signal_result (client,
607                      sl->name,
608                      request_id,
609                      GNUNET_ARM_RESULT_START_FAILED);
610   }
611   else
612   {
613     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
614                 _("Starting service `%s'\n"),
615                 sl->name);
616     broadcast_status (sl->name, GNUNET_ARM_SERVICE_STARTING, NULL);
617     if (client)
618       signal_result (client, sl->name, request_id, GNUNET_ARM_RESULT_STARTING);
619   }
620   /* clean up */
621   GNUNET_free (loprefix);
622   GNUNET_free (options);
623   GNUNET_array_grow (lsocks, ls, 0);
624 }
625
626
627 /**
628  * Find the process with the given service
629  * name in the given list and return it.
630  *
631  * @param name which service entry to look up
632  * @return NULL if it was not found
633  */
634 static struct ServiceList *
635 find_service (const char *name)
636 {
637   struct ServiceList *sl;
638
639   sl = running_head;
640   while (sl != NULL)
641     {
642       if (0 == strcasecmp (sl->name, name))
643         return sl;
644       sl = sl->next;
645     }
646   return NULL;
647 }
648
649
650 /**
651  * First connection has come to the listening socket associated with the service,
652  * create the service in order to relay the incoming connection to it
653  *
654  * @param cls callback data, `struct ServiceListeningInfo` describing a listen socket
655  */
656 static void
657 accept_connection (void *cls)
658 {
659   struct ServiceListeningInfo *sli = cls;
660   struct ServiceList *sl = sli->sl;
661
662   sli->accept_task = NULL;
663   GNUNET_assert (GNUNET_NO == in_shutdown);
664   start_process (sl, NULL, 0);
665 }
666
667
668 /**
669  * Creating a listening socket for each of the service's addresses and
670  * wait for the first incoming connection to it
671  *
672  * @param sa address associated with the service
673  * @param addr_len length of @a sa
674  * @param sl service entry for the service in question
675  */
676 static void
677 create_listen_socket (struct sockaddr *sa,
678                       socklen_t addr_len,
679                       struct ServiceList *sl)
680 {
681   static int on = 1;
682   struct GNUNET_NETWORK_Handle *sock;
683   struct ServiceListeningInfo *sli;
684 #ifndef WINDOWS
685   int match_uid;
686   int match_gid;
687 #endif
688
689   switch (sa->sa_family)
690   {
691   case AF_INET:
692     sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
693     break;
694   case AF_INET6:
695     sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
696     break;
697   case AF_UNIX:
698     if (strcmp (GNUNET_a2s (sa, addr_len), "@") == 0)   /* Do not bind to blank UNIX path! */
699       return;
700     sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
701     break;
702   default:
703     GNUNET_break (0);
704     sock = NULL;
705     errno = EAFNOSUPPORT;
706     break;
707   }
708   if (NULL == sock)
709   {
710     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
711                 _("Unable to create socket for service `%s': %s\n"),
712                 sl->name, STRERROR (errno));
713     GNUNET_free (sa);
714     return;
715   }
716   if (GNUNET_NETWORK_socket_setsockopt
717       (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
718     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
719                          "setsockopt");
720 #ifdef IPV6_V6ONLY
721   if ((sa->sa_family == AF_INET6) &&
722       (GNUNET_NETWORK_socket_setsockopt
723        (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK))
724     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
725                          "setsockopt");
726 #endif
727 #ifndef WINDOWS
728   if (AF_UNIX == sa->sa_family)
729     GNUNET_NETWORK_unix_precheck ((struct sockaddr_un *) sa);
730 #endif
731   if (GNUNET_OK !=
732       GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) sa, addr_len))
733   {
734     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
735                 _("Unable to bind listening socket for service `%s' to address `%s': %s\n"),
736                 sl->name,
737                 GNUNET_a2s (sa, addr_len),
738                 STRERROR (errno));
739     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
740     GNUNET_free (sa);
741     return;
742   }
743 #ifndef WINDOWS
744   if ((AF_UNIX == sa->sa_family)
745 #ifdef LINUX
746       /* Permission settings are not required when abstract sockets are used */
747       && ('\0' != ((const struct sockaddr_un *)sa)->sun_path[0])
748 #endif
749       )
750   {
751     match_uid =
752       GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name,
753                                             "UNIX_MATCH_UID");
754     match_gid =
755       GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name,
756                                             "UNIX_MATCH_GID");
757     GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sa)->sun_path,
758                                  match_uid,
759                                  match_gid);
760
761   }
762 #endif
763   if (GNUNET_NETWORK_socket_listen (sock, 5) != GNUNET_OK)
764   {
765     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
766     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
767     GNUNET_free (sa);
768     return;
769   }
770   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
771               _("ARM now monitors connections to service `%s' at `%s'\n"),
772               sl->name, GNUNET_a2s (sa, addr_len));
773   sli = GNUNET_new (struct ServiceListeningInfo);
774   sli->service_addr = sa;
775   sli->service_addr_len = addr_len;
776   sli->listen_socket = sock;
777   sli->sl = sl;
778   sli->accept_task =
779     GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sock,
780                                    &accept_connection, sli);
781   GNUNET_CONTAINER_DLL_insert (sl->listen_head,
782                                sl->listen_tail,
783                                sli);
784 }
785
786
787 /**
788  * Remove and free an entry in the service list.  Listen sockets
789  * must have already been cleaned up.  Only to be called during shutdown.
790  *
791  * @param sl entry to free
792  */
793 static void
794 free_service (struct ServiceList *sl)
795 {
796   GNUNET_assert (GNUNET_YES == in_shutdown);
797   GNUNET_CONTAINER_DLL_remove (running_head, running_tail, sl);
798   GNUNET_assert (NULL == sl->listen_head);
799   GNUNET_free_non_null (sl->config);
800   GNUNET_free_non_null (sl->binary);
801   GNUNET_free (sl->name);
802   GNUNET_free (sl);
803 }
804
805
806 /**
807  * Handle START-message.
808  *
809  * @param cls closure (always NULL)
810  * @param client identification of the client
811  * @param message the actual message
812  * @return #GNUNET_OK to keep the connection open,
813  *         #GNUNET_SYSERR to close it (signal serious error)
814  */
815 static void
816 handle_start (void *cls,
817               struct GNUNET_SERVER_Client *client,
818               const struct GNUNET_MessageHeader *message)
819 {
820   const char *servicename;
821   struct ServiceList *sl;
822   uint16_t size;
823   uint64_t request_id;
824   struct GNUNET_ARM_Message *amsg;
825
826   amsg = (struct GNUNET_ARM_Message *) message;
827   request_id = GNUNET_ntohll (amsg->request_id);
828   size = ntohs (amsg->header.size);
829   size -= sizeof (struct GNUNET_ARM_Message);
830   servicename = (const char *) &amsg[1];
831   if ((size == 0) || (servicename[size - 1] != '\0'))
832   {
833     GNUNET_break (0);
834     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
835     return;
836   }
837   if (GNUNET_YES == in_shutdown)
838   {
839     signal_result (client, servicename, request_id,
840                    GNUNET_ARM_RESULT_IN_SHUTDOWN);
841     GNUNET_SERVER_receive_done (client, GNUNET_OK);
842     return;
843   }
844   sl = find_service (servicename);
845   if (NULL == sl)
846   {
847     signal_result (client, servicename, request_id,
848                    GNUNET_ARM_RESULT_IS_NOT_KNOWN);
849     GNUNET_SERVER_receive_done (client, GNUNET_OK);
850     return;
851   }
852   sl->force_start = GNUNET_YES;
853   if (NULL != sl->proc)
854   {
855     signal_result (client, servicename, request_id,
856                    GNUNET_ARM_RESULT_IS_STARTED_ALREADY);
857     GNUNET_SERVER_receive_done (client, GNUNET_OK);
858     return;
859   }
860   start_process (sl, client, request_id);
861   GNUNET_SERVER_receive_done (client, GNUNET_OK);
862 }
863
864
865 /**
866  * Start a shutdown sequence.
867  *
868  * @param cls closure (refers to service)
869  */
870 static void
871 trigger_shutdown (void *cls)
872 {
873   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
874               "Triggering shutdown\n");
875   GNUNET_SCHEDULER_shutdown ();
876 }
877
878
879 /**
880  * Handle STOP-message.
881  *
882  * @param cls closure (always NULL)
883  * @param client identification of the client
884  * @param message the actual message
885  * @return #GNUNET_OK to keep the connection open,
886  *         #GNUNET_SYSERR to close it (signal serious error)
887  */
888 static void
889 handle_stop (void *cls,
890              struct GNUNET_SERVER_Client *client,
891              const struct GNUNET_MessageHeader *message)
892 {
893   struct ServiceList *sl;
894   const char *servicename;
895   uint16_t size;
896   uint64_t request_id;
897   struct GNUNET_ARM_Message *amsg;
898
899   amsg = (struct GNUNET_ARM_Message *) message;
900   request_id = GNUNET_ntohll (amsg->request_id);
901   size = ntohs (amsg->header.size);
902   size -= sizeof (struct GNUNET_ARM_Message);
903   servicename = (const char *) &amsg[1];
904   if ((size == 0) || (servicename[size - 1] != '\0'))
905     {
906       GNUNET_break (0);
907       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
908       return;
909     }
910   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
911               _("Preparing to stop `%s'\n"),
912               servicename);
913   if (0 == strcasecmp (servicename, "arm"))
914   {
915     broadcast_status (servicename,
916                       GNUNET_ARM_SERVICE_STOPPING, NULL);
917     signal_result (client,
918                    servicename,
919                    request_id,
920                    GNUNET_ARM_RESULT_STOPPING);
921     GNUNET_SERVER_client_persist_ (client);
922     GNUNET_SCHEDULER_add_now (&trigger_shutdown, NULL);
923     GNUNET_SERVER_receive_done (client, GNUNET_OK);
924     return;
925   }
926   sl = find_service (servicename);
927   if (sl == NULL)
928     {
929       signal_result (client,
930                      servicename,
931                      request_id,
932                      GNUNET_ARM_RESULT_IS_NOT_KNOWN);
933       GNUNET_SERVER_receive_done (client, GNUNET_OK);
934       return;
935     }
936   sl->force_start = GNUNET_NO;
937   if (GNUNET_YES == in_shutdown)
938     {
939       /* shutdown in progress */
940       signal_result (client,
941                      servicename,
942                      request_id,
943                      GNUNET_ARM_RESULT_IN_SHUTDOWN);
944       GNUNET_SERVER_receive_done (client, GNUNET_OK);
945       return;
946     }
947   if (NULL != sl->killing_client)
948   {
949     /* killing already in progress */
950     signal_result (client,
951                    servicename,
952                    request_id,
953                    GNUNET_ARM_RESULT_IS_STOPPING_ALREADY);
954     GNUNET_SERVER_receive_done (client, GNUNET_OK);
955     return;
956   }
957   if (NULL == sl->proc)
958   {
959     /* process is down */
960     signal_result (client,
961                    servicename,
962                    request_id,
963                    GNUNET_ARM_RESULT_IS_STOPPED_ALREADY);
964     GNUNET_SERVER_receive_done (client, GNUNET_OK);
965     return;
966   }
967   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
968               "Sending kill signal to service `%s', waiting for process to die.\n",
969               servicename);
970   broadcast_status (servicename,
971                     GNUNET_ARM_SERVICE_STOPPING,
972                     NULL);
973   /* no signal_start - only when it's STOPPED */
974   sl->killed_at = GNUNET_TIME_absolute_get ();
975   if (0 != GNUNET_OS_process_kill (sl->proc, GNUNET_TERM_SIG))
976     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
977   sl->killing_client = client;
978   sl->killing_client_request_id = request_id;
979   GNUNET_SERVER_client_keep (client);
980   GNUNET_SERVER_receive_done (client, GNUNET_OK);
981 }
982
983
984 /**
985  * Handle LIST-message.
986  *
987  * @param cls closure (always NULL)
988  * @param client identification of the client
989  * @param message the actual message
990  */
991 static void
992 handle_list (void *cls,
993              struct GNUNET_SERVER_Client *client,
994              const struct GNUNET_MessageHeader *message)
995 {
996   struct GNUNET_ARM_ListResultMessage *msg;
997   struct GNUNET_ARM_Message *request;
998   size_t string_list_size;
999   size_t total_size;
1000   struct ServiceList *sl;
1001   uint16_t count;
1002
1003   if (NULL == client)
1004     return;
1005
1006   request = (struct GNUNET_ARM_Message *) message;
1007   GNUNET_break (0 == ntohl (request->reserved));
1008   count = 0;
1009   string_list_size = 0;
1010   /* first count the running processes get their name's size */
1011   for (sl = running_head; NULL != sl; sl = sl->next)
1012   {
1013     if (NULL != sl->proc)
1014     {
1015       string_list_size += strlen (sl->name);
1016       string_list_size += strlen (sl->binary);
1017       string_list_size += 4;
1018       count++;
1019     }
1020   }
1021
1022   total_size = sizeof (struct GNUNET_ARM_ListResultMessage)
1023                + string_list_size;
1024   msg = GNUNET_malloc (total_size);
1025   msg->arm_msg.header.size = total_size;
1026   msg->arm_msg.header.type = GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT;
1027   msg->arm_msg.reserved = htonl (0);
1028   msg->arm_msg.request_id = GNUNET_ntohll (request->request_id);
1029   msg->count = count;
1030
1031   char *pos = (char *)&msg[1];
1032   for (sl = running_head; NULL != sl; sl = sl->next)
1033   {
1034     if (NULL != sl->proc)
1035     {
1036       size_t s = strlen (sl->name) + strlen (sl->binary) + 4;
1037       GNUNET_snprintf (pos, s, "%s (%s)", sl->name, sl->binary);
1038       pos += s;
1039     }
1040   }
1041   GNUNET_SERVER_notify_transmit_ready (client,
1042                                        total_size,
1043                                        GNUNET_TIME_UNIT_FOREVER_REL,
1044                                        &write_list_result, msg);
1045   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1046 }
1047
1048
1049 /**
1050  * We are done with everything.  Stop remaining
1051  * tasks, signal handler and the server.
1052  */
1053 static void
1054 do_shutdown ()
1055 {
1056   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Last shutdown phase\n");
1057   if (NULL != notifier)
1058   {
1059     GNUNET_SERVER_notification_context_destroy (notifier);
1060     notifier = NULL;
1061   }
1062   if (NULL != server)
1063     {
1064       GNUNET_SERVER_destroy (server);
1065       server = NULL;
1066     }
1067   if (NULL != child_death_task)
1068     {
1069       GNUNET_SCHEDULER_cancel (child_death_task);
1070       child_death_task = NULL;
1071     }
1072 }
1073
1074
1075 /**
1076  * Count how many services are still active.
1077  *
1078  * @param running_head list of services
1079  * @return number of active services found
1080  */
1081 static unsigned int
1082 list_count (struct ServiceList *running_head)
1083 {
1084   struct ServiceList *i;
1085   unsigned int res = 0;
1086
1087   for (res = 0, i = running_head; i; i = i->next, res++)
1088     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1089                 "%s\n",
1090                 i->name);
1091   return res;
1092 }
1093
1094
1095 /**
1096  * Task run for shutdown.
1097  *
1098  * @param cls closure, NULL if we need to self-restart
1099  */
1100 static void
1101 shutdown_task (void *cls)
1102 {
1103   struct ServiceList *pos;
1104   struct ServiceList *nxt;
1105   struct ServiceListeningInfo *sli;
1106
1107   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1108               "First shutdown phase\n");
1109   if (NULL != child_restart_task)
1110   {
1111     GNUNET_SCHEDULER_cancel (child_restart_task);
1112     child_restart_task = NULL;
1113   }
1114   in_shutdown = GNUNET_YES;
1115   /* first, stop listening */
1116   for (pos = running_head; NULL != pos; pos = pos->next)
1117   {
1118     while (NULL != (sli = pos->listen_head))
1119       {
1120         GNUNET_CONTAINER_DLL_remove (pos->listen_head,
1121                                      pos->listen_tail,
1122                                      sli);
1123         if (NULL != sli->accept_task)
1124           {
1125             GNUNET_SCHEDULER_cancel (sli->accept_task);
1126             sli->accept_task = NULL;
1127           }
1128         GNUNET_break (GNUNET_OK ==
1129                       GNUNET_NETWORK_socket_close (sli->listen_socket));
1130         GNUNET_free (sli->service_addr);
1131         GNUNET_free (sli);
1132       }
1133   }
1134   /* then, shutdown all existing service processes */
1135   nxt = running_head;
1136   while (NULL != (pos = nxt))
1137   {
1138     nxt = pos->next;
1139     if (NULL != pos->proc)
1140     {
1141       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1142                   "Stopping service `%s'\n",
1143                   pos->name);
1144       pos->killed_at = GNUNET_TIME_absolute_get ();
1145       if (0 != GNUNET_OS_process_kill (pos->proc, GNUNET_TERM_SIG))
1146         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
1147     }
1148     else
1149     {
1150       free_service (pos);
1151     }
1152   }
1153   /* finally, should all service processes be already gone, terminate for real */
1154   if (NULL == running_head)
1155     do_shutdown ();
1156   else
1157     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1158                 "Delaying shutdown, have %u childs still running\n",
1159                 list_count (running_head));
1160 }
1161
1162
1163 /**
1164  * Task run whenever it is time to restart a child that died.
1165  *
1166  * @param cls closure, always NULL
1167  */
1168 static void
1169 delayed_restart_task (void *cls)
1170
1171 {
1172   struct ServiceList *sl;
1173   struct GNUNET_TIME_Relative lowestRestartDelay;
1174   struct ServiceListeningInfo *sli;
1175
1176   child_restart_task = NULL;
1177   GNUNET_assert (GNUNET_NO == in_shutdown);
1178   lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL;
1179
1180   /* check for services that need to be restarted due to
1181    * configuration changes or because the last restart failed */
1182   for (sl = running_head; NULL != sl; sl = sl->next)
1183   {
1184     if (NULL != sl->proc)
1185       continue;
1186     /* service is currently not running */
1187     if (0 == GNUNET_TIME_absolute_get_remaining (sl->restart_at).rel_value_us)
1188     {
1189       /* restart is now allowed */
1190       if (sl->force_start)
1191       {
1192         /* process should run by default, start immediately */
1193         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1194                     _("Restarting service `%s'.\n"),
1195                     sl->name);
1196         start_process (sl, NULL, 0);
1197       }
1198       else
1199       {
1200         /* process is run on-demand, ensure it is re-started if there is demand */
1201         for (sli = sl->listen_head; NULL != sli; sli = sli->next)
1202           if (NULL == sli->accept_task)
1203           {
1204             /* accept was actually paused, so start it again */
1205             sli->accept_task =
1206               GNUNET_SCHEDULER_add_read_net
1207               (GNUNET_TIME_UNIT_FOREVER_REL,
1208                sli->listen_socket,
1209                &accept_connection, sli);
1210           }
1211       }
1212     }
1213     else
1214     {
1215       /* update calculation for earliest time to reactivate a service */
1216       lowestRestartDelay =
1217         GNUNET_TIME_relative_min (lowestRestartDelay,
1218                                   GNUNET_TIME_absolute_get_remaining
1219                                   (sl->restart_at));
1220     }
1221   }
1222   if (lowestRestartDelay.rel_value_us != GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1223   {
1224     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1225                 "Will restart process in %s\n",
1226                 GNUNET_STRINGS_relative_time_to_string (lowestRestartDelay, GNUNET_YES));
1227     child_restart_task =
1228       GNUNET_SCHEDULER_add_delayed_with_priority (lowestRestartDelay,
1229                                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
1230                                                   &delayed_restart_task, NULL);
1231   }
1232 }
1233
1234
1235 /**
1236  * Task triggered whenever we receive a SIGCHLD (child
1237  * process died).
1238  *
1239  * @param cls closure, NULL if we need to self-restart
1240  */
1241 static void
1242 maint_child_death (void *cls)
1243 {
1244   struct ServiceList *pos;
1245   struct ServiceList *next;
1246   struct ServiceListeningInfo *sli;
1247   const char *statstr;
1248   int statcode;
1249   int ret;
1250   char c[16];
1251   enum GNUNET_OS_ProcessStatusType statusType;
1252   unsigned long statusCode;
1253   const struct GNUNET_DISK_FileHandle *pr;
1254
1255   pr = GNUNET_DISK_pipe_handle (sigpipe,
1256                                 GNUNET_DISK_PIPE_END_READ);
1257   child_death_task = NULL;
1258   /* consume the signal */
1259   GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
1260
1261   /* check for services that died (WAITPID) */
1262   next = running_head;
1263   while (NULL != (pos = next))
1264   {
1265     next = pos->next;
1266
1267     if (NULL == pos->proc)
1268     {
1269       if (GNUNET_YES == in_shutdown)
1270         free_service (pos);
1271       continue;
1272     }
1273 #if HAVE_WAIT4
1274     if (NULL != wait_file)
1275     {
1276       /* need to use 'wait4()' to obtain and log performance data */
1277       struct rusage ru;
1278       int status;
1279       pid_t pid;
1280
1281       pid = GNUNET_OS_process_get_pid (pos->proc);
1282       ret = wait4 (pid,
1283                    &status,
1284                    WNOHANG,
1285                    &ru);
1286       if (ret <= 0)
1287         continue; /* no process done */
1288       if (WIFEXITED (status))
1289       {
1290         statusType = GNUNET_OS_PROCESS_EXITED;
1291         statusCode = WEXITSTATUS (status);
1292       }
1293       else if (WIFSIGNALED (status))
1294       {
1295         statusType = GNUNET_OS_PROCESS_SIGNALED;
1296         statusCode = WTERMSIG (status);
1297       }
1298       else if (WIFSTOPPED (status))
1299       {
1300         statusType = GNUNET_OS_PROCESS_SIGNALED;
1301         statusCode = WSTOPSIG (status);
1302       }
1303 #ifdef WIFCONTINUED
1304       else if (WIFCONTINUED (status))
1305       {
1306         statusType = GNUNET_OS_PROCESS_RUNNING;
1307         statusCode = 0;
1308       }
1309 #endif
1310       else
1311       {
1312         statusType = GNUNET_OS_PROCESS_UNKNOWN;
1313         statusCode = 0;
1314       }
1315       if ( (GNUNET_OS_PROCESS_EXITED == statusType) ||
1316            (GNUNET_OS_PROCESS_SIGNALED == statusType) )
1317       {
1318         double utime = ru.ru_utime.tv_sec + (ru.ru_utime.tv_usec / 10e6);
1319         double stime = ru.ru_stime.tv_sec + (ru.ru_stime.tv_usec / 10e6);
1320         fprintf (wait_file,
1321                  "%s(%u) %.3f %.3f %llu %llu %llu %llu %llu\n",
1322                  pos->binary,
1323                  (unsigned int) pid,
1324                  utime,
1325                  stime,
1326                  (unsigned long long) ru.ru_maxrss,
1327                  (unsigned long long) ru.ru_inblock,
1328                  (unsigned long long) ru.ru_oublock,
1329                  (unsigned long long) ru.ru_nvcsw,
1330                  (unsigned long long) ru.ru_nivcsw);
1331       }
1332     }
1333     else /* continue with JUST this "if" as "else" (intentionally no brackets!) */
1334 #endif
1335     if ( (GNUNET_SYSERR ==
1336           (ret =
1337            GNUNET_OS_process_status (pos->proc,
1338                                      &statusType,
1339                                      &statusCode))) ||
1340          (ret == GNUNET_NO) ||
1341          (statusType == GNUNET_OS_PROCESS_STOPPED) ||
1342          (statusType == GNUNET_OS_PROCESS_UNKNOWN) ||
1343          (statusType == GNUNET_OS_PROCESS_RUNNING) )
1344       continue;
1345
1346     if (statusType == GNUNET_OS_PROCESS_EXITED)
1347     {
1348       statstr = _( /* process termination method */ "exit");
1349       statcode = statusCode;
1350     }
1351     else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
1352     {
1353       statstr = _( /* process termination method */ "signal");
1354       statcode = statusCode;
1355     }
1356     else
1357     {
1358       statstr = _( /* process termination method */ "unknown");
1359       statcode = 0;
1360     }
1361     if (0 != pos->killed_at.abs_value_us)
1362     {
1363       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1364                   _("Service `%s' took %s to terminate\n"),
1365                   pos->name,
1366                   GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->killed_at),
1367                                                           GNUNET_YES));
1368     }
1369     GNUNET_OS_process_destroy (pos->proc);
1370     pos->proc = NULL;
1371     broadcast_status (pos->name,
1372                       GNUNET_ARM_SERVICE_STOPPED,
1373                       NULL);
1374     if (NULL != pos->killing_client)
1375     {
1376       signal_result (pos->killing_client, pos->name,
1377                      pos->killing_client_request_id,
1378                      GNUNET_ARM_RESULT_STOPPED);
1379       GNUNET_SERVER_client_drop (pos->killing_client);
1380       pos->killing_client = NULL;
1381       pos->killing_client_request_id = 0;
1382     }
1383     if (GNUNET_YES != in_shutdown)
1384     {
1385       if ( (statusType == GNUNET_OS_PROCESS_EXITED) &&
1386            (statcode == 0) )
1387       {
1388         /* process terminated normally, allow restart at any time */
1389         pos->restart_at.abs_value_us = 0;
1390         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1391                     _("Service `%s' terminated normally, will restart at any time\n"),
1392                     pos->name);
1393         /* process can still be re-started on-demand, ensure it is re-started if there is demand */
1394         for (sli = pos->listen_head; NULL != sli; sli = sli->next)
1395         {
1396           GNUNET_break (NULL == sli->accept_task);
1397           sli->accept_task =
1398             GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1399                                            sli->listen_socket,
1400                                            &accept_connection,
1401                                            sli);
1402         }
1403       }
1404       else
1405       {
1406         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1407                     _("Service `%s' terminated with status %s/%d, will restart in %s\n"),
1408                     pos->name,
1409                     statstr,
1410                     statcode,
1411                     GNUNET_STRINGS_relative_time_to_string (pos->backoff,
1412                                                             GNUNET_YES));
1413         /* schedule restart */
1414         pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff);
1415         pos->backoff = GNUNET_TIME_STD_BACKOFF (pos->backoff);
1416         if (NULL != child_restart_task)
1417           GNUNET_SCHEDULER_cancel (child_restart_task);
1418         child_restart_task
1419           = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
1420                                                 &delayed_restart_task,
1421                                                 NULL);
1422       }
1423     }
1424     else
1425     {
1426       free_service (pos);
1427     }
1428   }
1429   child_death_task = GNUNET_SCHEDULER_add_read_file (
1430       GNUNET_TIME_UNIT_FOREVER_REL,
1431       pr,
1432       &maint_child_death, NULL);
1433   if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
1434     do_shutdown ();
1435   else if (GNUNET_YES == in_shutdown)
1436     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1437         "Delaying shutdown after child's death, still have %u children\n",
1438         list_count (running_head));
1439
1440 }
1441
1442
1443 /**
1444  * Signal handler called for SIGCHLD.  Triggers the
1445  * respective handler by writing to the trigger pipe.
1446  */
1447 static void
1448 sighandler_child_death ()
1449 {
1450   static char c;
1451   int old_errno = errno;        /* back-up errno */
1452
1453   GNUNET_break (1 ==
1454                 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
1455                                         (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
1456                                         &c, sizeof (c)));
1457   errno = old_errno;            /* restore errno */
1458 }
1459
1460
1461 /**
1462  * Setup our service record for the given section in the configuration file
1463  * (assuming the section is for a service).
1464  *
1465  * @param cls unused
1466  * @param section a section in the configuration file
1467  * @return #GNUNET_OK (continue)
1468  */
1469 static void
1470 setup_service (void *cls,
1471                const char *section)
1472 {
1473   struct ServiceList *sl;
1474   char *binary;
1475   char *config;
1476   struct stat sbuf;
1477   struct sockaddr **addrs;
1478   socklen_t *addr_lens;
1479   int ret;
1480   unsigned int i;
1481
1482   if (strcasecmp (section, "arm") == 0)
1483     return;
1484   if (GNUNET_OK !=
1485       GNUNET_CONFIGURATION_get_value_string (cfg, section, "BINARY", &binary))
1486   {
1487     /* not a service section */
1488     return;
1489   }
1490   if ((GNUNET_YES ==
1491        GNUNET_CONFIGURATION_have_value (cfg, section, "USER_SERVICE")) &&
1492       (GNUNET_YES ==
1493        GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "USER_SERVICE")))
1494   {
1495     if (GNUNET_NO == start_user)
1496     {
1497       GNUNET_free (binary);
1498       return; /* user service, and we don't deal with those */
1499     }
1500   }
1501   else
1502   {
1503     if (GNUNET_NO == start_system)
1504     {
1505       GNUNET_free (binary);
1506       return; /* system service, and we don't deal with those */
1507     }
1508   }
1509   sl = find_service (section);
1510   if (NULL != sl)
1511   {
1512     /* got the same section twice!? */
1513     GNUNET_break (0);
1514     GNUNET_free (binary);
1515     return;
1516   }
1517   config = NULL;
1518   if (( (GNUNET_OK !=
1519          GNUNET_CONFIGURATION_get_value_filename (cfg, section,
1520                                                   "CONFIG",
1521                                                   &config)) &&
1522         (GNUNET_OK !=
1523          GNUNET_CONFIGURATION_get_value_filename (cfg,
1524                                                   "PATHS",
1525                                                   "DEFAULTCONFIG",
1526                                                   &config)) ) ||
1527       (0 != STAT (config, &sbuf)))
1528   {
1529     if (NULL != config)
1530     {
1531       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1532                                  section, "CONFIG",
1533                                  STRERROR (errno));
1534       GNUNET_free (config);
1535       config = NULL;
1536     }
1537   }
1538   sl = GNUNET_new (struct ServiceList);
1539   sl->name = GNUNET_strdup (section);
1540   sl->binary = binary;
1541   sl->config = config;
1542   sl->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
1543   sl->restart_at = GNUNET_TIME_UNIT_FOREVER_ABS;
1544 #if WINDOWS
1545   sl->pipe_control = GNUNET_YES;
1546 #else
1547   if (GNUNET_CONFIGURATION_have_value (cfg,
1548                                        section,
1549                                        "PIPECONTROL"))
1550     sl->pipe_control = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1551                                                              section,
1552                                                              "PIPECONTROL");
1553 #endif
1554   GNUNET_CONTAINER_DLL_insert (running_head,
1555                                running_tail,
1556                                sl);
1557   if (GNUNET_YES ==
1558       GNUNET_CONFIGURATION_get_value_yesno (cfg,
1559                                             section,
1560                                             "FORCESTART"))
1561   {
1562     sl->force_start = GNUNET_YES;
1563     if (GNUNET_YES ==
1564         GNUNET_CONFIGURATION_get_value_yesno (cfg,
1565                                               section,
1566                                               "NOARMBIND"))
1567       return;
1568   }
1569   else
1570   {
1571     if (GNUNET_YES !=
1572         GNUNET_CONFIGURATION_get_value_yesno (cfg,
1573                                               section,
1574                                               "AUTOSTART"))
1575       return;
1576   }
1577   if (0 >= (ret = GNUNET_SERVICE_get_server_addresses (section,
1578                                                        cfg,
1579                                                        &addrs,
1580                                                        &addr_lens)))
1581     return;
1582   /* this will free (or capture) addrs[i] */
1583   for (i = 0; i < ret; i++)
1584     create_listen_socket (addrs[i],
1585                           addr_lens[i],
1586                           sl);
1587   GNUNET_free (addrs);
1588   GNUNET_free (addr_lens);
1589 }
1590
1591
1592 /**
1593  * A client connected, add it to the notification context.
1594  *
1595  * @param cls closure
1596  * @param client identification of the client
1597  */
1598 static void
1599 handle_client_connecting (void *cls,
1600                           struct GNUNET_SERVER_Client *client)
1601 {
1602   /* All clients are considered to be of the "monitor" kind
1603    * (that is, they don't affect ARM shutdown).
1604    */
1605   if (NULL != client)
1606     GNUNET_SERVER_client_mark_monitor (client);
1607 }
1608
1609
1610 /**
1611  * Handle MONITOR-message.
1612  *
1613  * @param cls closure (always NULL)
1614  * @param client identification of the client
1615  * @param message the actual message
1616  * @return #GNUNET_OK to keep the connection open,
1617  *         #GNUNET_SYSERR to close it (signal serious error)
1618  */
1619 static void
1620 handle_monitor (void *cls,
1621                 struct GNUNET_SERVER_Client *client,
1622                 const struct GNUNET_MessageHeader *message)
1623 {
1624   /* FIXME: might want to start by letting monitor know about
1625      services that are already running */
1626   /* Removal is handled by the server implementation, internally. */
1627   if ((NULL != client) && (NULL != notifier))
1628   {
1629     GNUNET_SERVER_notification_context_add (notifier, client);
1630     broadcast_status ("arm", GNUNET_ARM_SERVICE_MONITORING_STARTED, client);
1631     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1632   }
1633 }
1634
1635
1636 /**
1637  * Process arm requests.
1638  *
1639  * @param cls closure
1640  * @param serv the initialized server
1641  * @param c configuration to use
1642  */
1643 static void
1644 run (void *cls, struct GNUNET_SERVER_Handle *serv,
1645      const struct GNUNET_CONFIGURATION_Handle *c)
1646 {
1647   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1648     {&handle_start, NULL, GNUNET_MESSAGE_TYPE_ARM_START, 0},
1649     {&handle_stop, NULL, GNUNET_MESSAGE_TYPE_ARM_STOP, 0},
1650     {&handle_monitor, NULL, GNUNET_MESSAGE_TYPE_ARM_MONITOR,
1651      sizeof (struct GNUNET_MessageHeader)},
1652     {&handle_list, NULL, GNUNET_MESSAGE_TYPE_ARM_LIST,
1653      sizeof (struct GNUNET_ARM_Message)},
1654     {NULL, NULL, 0, 0}
1655   };
1656   struct ServiceList *sl;
1657
1658   cfg = c;
1659   server = serv;
1660   GNUNET_assert (NULL != serv);
1661   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1662                                  NULL);
1663   child_death_task =
1664     GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1665                                     GNUNET_DISK_pipe_handle (sigpipe,
1666                                                              GNUNET_DISK_PIPE_END_READ),
1667                                     &maint_child_death, NULL);
1668 #if HAVE_WAIT4
1669   if (GNUNET_OK ==
1670       GNUNET_CONFIGURATION_get_value_filename (cfg,
1671                                                "ARM",
1672                                                "RESOURCE_DIAGNOSTICS",
1673                                                &wait_filename))
1674   {
1675     wait_file = fopen (wait_filename,
1676                        "w");
1677     if (NULL == wait_file)
1678     {
1679       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1680                                 "fopen",
1681                                 wait_filename);
1682     }
1683   }
1684 #endif
1685   if (GNUNET_OK !=
1686       GNUNET_CONFIGURATION_get_value_string (cfg,
1687                                              "ARM",
1688                                              "GLOBAL_PREFIX",
1689                                              &prefix_command))
1690     prefix_command = GNUNET_strdup ("");
1691   if (GNUNET_OK !=
1692       GNUNET_CONFIGURATION_get_value_string (cfg,
1693                                              "ARM",
1694                                              "GLOBAL_POSTFIX",
1695                                              &final_option))
1696     final_option = GNUNET_strdup ("");
1697   if (GNUNET_YES ==
1698       GNUNET_CONFIGURATION_get_value_yesno (cfg,
1699                                             "ARM",
1700                                             "USER_ONLY"))
1701   {
1702     GNUNET_break (GNUNET_YES == start_user);
1703     start_system = GNUNET_NO;
1704   }
1705   if (GNUNET_YES ==
1706       GNUNET_CONFIGURATION_get_value_yesno (cfg,
1707                                             "ARM",
1708                                             "SYSTEM_ONLY"))
1709   {
1710     GNUNET_break (GNUNET_YES == start_system);
1711     start_user = GNUNET_NO;
1712   }
1713   GNUNET_CONFIGURATION_iterate_sections (cfg, &setup_service, NULL);
1714
1715   /* start default services... */
1716   for (sl = running_head; NULL != sl; sl = sl->next)
1717     if (GNUNET_YES == sl->force_start)
1718       start_process (sl, NULL, 0);
1719   notifier
1720     = GNUNET_SERVER_notification_context_create (server,
1721                                                  MAX_NOTIFY_QUEUE);
1722   GNUNET_SERVER_connect_notify (server,
1723                                 &handle_client_connecting, NULL);
1724   /* process client requests */
1725   GNUNET_SERVER_add_handlers (server,
1726                               handlers);
1727 }
1728
1729
1730 /**
1731  * The main function for the arm service.
1732  *
1733  * @param argc number of arguments from the command line
1734  * @param argv command line arguments
1735  * @return 0 ok, 1 on error
1736  */
1737 int
1738 main (int argc, char *const *argv)
1739 {
1740   int ret;
1741   struct GNUNET_SIGNAL_Context *shc_chld;
1742
1743   sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
1744   GNUNET_assert (sigpipe != NULL);
1745   shc_chld =
1746     GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
1747   ret =
1748     (GNUNET_OK ==
1749      GNUNET_SERVICE_run (argc, argv, "arm",
1750                          GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN, &run, NULL)) ? 0 : 1;
1751 #if HAVE_WAIT4
1752   if (NULL != wait_file)
1753   {
1754     fclose (wait_file);
1755     wait_file = NULL;
1756   }
1757   if (NULL != wait_filename)
1758   {
1759     GNUNET_free (wait_filename);
1760     wait_filename = NULL;
1761   }
1762 #endif
1763   GNUNET_SIGNAL_handler_uninstall (shc_chld);
1764   shc_chld = NULL;
1765   GNUNET_DISK_pipe_close (sigpipe);
1766   sigpipe = NULL;
1767   return ret;
1768 }
1769
1770
1771 #if defined(LINUX) && defined(__GLIBC__)
1772 #include <malloc.h>
1773
1774 /**
1775  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1776  */
1777 void __attribute__ ((constructor)) GNUNET_ARM_memory_init ()
1778 {
1779   mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1780   mallopt (M_TOP_PAD, 1 * 1024);
1781   malloc_trim (0);
1782 }
1783 #endif
1784
1785
1786 /* end of gnunet-service-arm.c */