implement exponential back-off cool down for ARM process restarts
[oweals/gnunet.git] / src / arm / gnunet-service-arm.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009-2011, 2015, 2016 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 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
33
34 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
35
36
37 #if HAVE_WAIT4
38 /**
39  * Name of the file for writing resource utilization summaries to.
40  */
41 static char *wait_filename;
42
43 /**
44  * Handle for the file for writing resource summaries.
45  */
46 static FILE *wait_file;
47 #endif
48
49
50 /**
51  * How many messages do we queue up at most for optional
52  * notifications to a client?  (this can cause notifications
53  * about outgoing messages to be dropped).
54  */
55 #define MAX_NOTIFY_QUEUE 1024
56
57
58 /**
59  * List of our services.
60  */
61 struct ServiceList;
62
63
64 /**
65  * Record with information about a listen socket we have open.
66  */
67 struct ServiceListeningInfo
68 {
69   /**
70    * This is a linked list.
71    */
72   struct ServiceListeningInfo *next;
73
74   /**
75    * This is a linked list.
76    */
77   struct ServiceListeningInfo *prev;
78
79   /**
80    * Address this socket is listening on.
81    */
82   struct sockaddr *service_addr;
83
84   /**
85    * Service this listen socket is for.
86    */
87   struct ServiceList *sl;
88
89   /**
90    * Number of bytes in @e service_addr
91    */
92   socklen_t service_addr_len;
93
94   /**
95    * Our listening socket.
96    */
97   struct GNUNET_NETWORK_Handle *listen_socket;
98
99   /**
100    * Task doing the accepting.
101    */
102   struct GNUNET_SCHEDULER_Task *accept_task;
103
104 };
105
106
107 /**
108  * List of our services.
109  */
110 struct ServiceList
111 {
112   /**
113    * This is a doubly-linked list.
114    */
115   struct ServiceList *next;
116
117   /**
118    * This is a doubly-linked list.
119    */
120   struct ServiceList *prev;
121
122   /**
123    * Linked list of listen sockets associated with this service.
124    */
125   struct ServiceListeningInfo *listen_head;
126
127   /**
128    * Linked list of listen sockets associated with this service.
129    */
130   struct ServiceListeningInfo *listen_tail;
131
132   /**
133    * Name of the service.
134    */
135   char *name;
136
137   /**
138    * Name of the binary used.
139    */
140   char *binary;
141
142   /**
143    * Name of the configuration file used.
144    */
145   char *config;
146
147   /**
148    * Client to notify upon kill completion (waitpid), NULL
149    * if we should simply restart the process.
150    */
151   struct GNUNET_SERVICE_Client *killing_client;
152
153   /**
154    * ID of the request that killed the service (for reporting back).
155    */
156   uint64_t killing_client_request_id;
157
158   /**
159    * Process structure pointer of the child.
160    */
161   struct GNUNET_OS_Process *proc;
162
163   /**
164    * Process exponential backoff time
165    */
166   struct GNUNET_TIME_Relative backoff;
167
168   /**
169    * Absolute time at which the process is scheduled to restart in case of death
170    */
171   struct GNUNET_TIME_Absolute restart_at;
172
173   /**
174    * Time we asked the service to shut down (used to calculate time it took
175    * the service to terminate).
176    */
177   struct GNUNET_TIME_Absolute killed_at;
178
179   /**
180    * Is this service to be started by default (or did a client tell us explicitly
181    * to start it)?  #GNUNET_NO if the service is started only upon 'accept' on a
182    * listen socket or possibly explicitly by a client changing the value.
183    */
184   int force_start;
185
186   /**
187    * Should we use pipes to signal this process? (YES for Java binaries and if we
188    * are on Windoze).
189    */
190   int pipe_control;
191 };
192
193 /**
194  * List of running services.
195  */
196 static struct ServiceList *running_head;
197
198 /**
199  * List of running services.
200  */
201 static struct ServiceList *running_tail;
202
203 /**
204  * Our configuration
205  */
206 static const struct GNUNET_CONFIGURATION_Handle *cfg;
207
208 /**
209  * Command to prepend to each actual command.
210  */
211 static char *prefix_command;
212
213 /**
214  * Option to append to each actual command.
215  */
216 static char *final_option;
217
218 /**
219  * ID of task called whenever we get a SIGCHILD.
220  */
221 static struct GNUNET_SCHEDULER_Task *child_death_task;
222
223 /**
224  * ID of task called whenever the timeout for restarting a child
225  * expires.
226  */
227 static struct GNUNET_SCHEDULER_Task *child_restart_task;
228
229 /**
230  * Pipe used to communicate shutdown via signal.
231  */
232 static struct GNUNET_DISK_PipeHandle *sigpipe;
233
234 /**
235  * Are we in shutdown mode?
236  */
237 static int in_shutdown;
238
239 /**
240  * Are we starting user services?
241  */
242 static int start_user = GNUNET_YES;
243
244 /**
245  * Are we starting system services?
246  */
247 static int start_system = GNUNET_YES;
248
249 /**
250  * Handle to our service instance.  Our service is a bit special in that
251  * its service is not immediately stopped once we get a shutdown
252  * request (since we need to continue service until all of our child
253  * processes are dead).  This handle is used to shut down the service
254  * (and thus trigger process termination) once all child processes are
255  * also dead.  A special option in the ARM configuration modifies the
256  * behaviour of the service implementation to not do the shutdown
257  * immediately.
258  */
259 static struct GNUNET_SERVICE_Handle *service;
260
261 /**
262  * Context for notifications we need to send to our clients.
263  */
264 static struct GNUNET_NotificationContext *notifier;
265
266
267 /**
268  * Add the given UNIX domain path as an address to the
269  * list (as the first entry).
270  *
271  * @param saddrs array to update
272  * @param saddrlens where to store the address length
273  * @param unixpath path to add
274  * @param abstract #GNUNET_YES to add an abstract UNIX domain socket.  This
275  *          parameter is ignore on systems other than LINUX
276  */
277 static void
278 add_unixpath (struct sockaddr **saddrs,
279               socklen_t *saddrlens,
280               const char *unixpath,
281               int abstract)
282 {
283 #ifdef AF_UNIX
284   struct sockaddr_un *un;
285
286   un = GNUNET_new (struct sockaddr_un);
287   un->sun_family = AF_UNIX;
288   strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
289 #ifdef LINUX
290   if (GNUNET_YES == abstract)
291     un->sun_path[0] = '\0';
292 #endif
293 #if HAVE_SOCKADDR_UN_SUN_LEN
294   un->sun_len = (u_char) sizeof (struct sockaddr_un);
295 #endif
296   *saddrs = (struct sockaddr *) un;
297   *saddrlens = sizeof (struct sockaddr_un);
298 #else
299   /* this function should never be called
300    * unless AF_UNIX is defined! */
301   GNUNET_assert (0);
302 #endif
303 }
304
305
306 /**
307  * Get the list of addresses that a server for the given service
308  * should bind to.
309  *
310  * @param service_name name of the service
311  * @param cfg configuration (which specifies the addresses)
312  * @param addrs set (call by reference) to an array of pointers to the
313  *              addresses the server should bind to and listen on; the
314  *              array will be NULL-terminated (on success)
315  * @param addr_lens set (call by reference) to an array of the lengths
316  *              of the respective `struct sockaddr` struct in the @a addrs
317  *              array (on success)
318  * @return number of addresses found on success,
319  *              #GNUNET_SYSERR if the configuration
320  *              did not specify reasonable finding information or
321  *              if it specified a hostname that could not be resolved;
322  *              #GNUNET_NO if the number of addresses configured is
323  *              zero (in this case, `*addrs` and `*addr_lens` will be
324  *              set to NULL).
325  */
326 static int
327 get_server_addresses (const char *service_name,
328                       const struct GNUNET_CONFIGURATION_Handle *cfg,
329                       struct sockaddr ***addrs,
330                       socklen_t ** addr_lens)
331 {
332   int disablev6;
333   struct GNUNET_NETWORK_Handle *desc;
334   unsigned long long port;
335   char *unixpath;
336   struct addrinfo hints;
337   struct addrinfo *res;
338   struct addrinfo *pos;
339   struct addrinfo *next;
340   unsigned int i;
341   int resi;
342   int ret;
343   int abstract;
344   struct sockaddr **saddrs;
345   socklen_t *saddrlens;
346   char *hostname;
347
348   *addrs = NULL;
349   *addr_lens = NULL;
350   desc = NULL;
351   if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
352   {
353     if (GNUNET_SYSERR ==
354         (disablev6 =
355          GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
356       return GNUNET_SYSERR;
357   }
358   else
359     disablev6 = GNUNET_NO;
360
361   if (! disablev6)
362   {
363     /* probe IPv6 support */
364     desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
365     if (NULL == desc)
366     {
367       if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
368           (EACCES == errno))
369       {
370         LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
371         return GNUNET_SYSERR;
372       }
373       LOG (GNUNET_ERROR_TYPE_INFO,
374            _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
375            service_name, STRERROR (errno));
376       disablev6 = GNUNET_YES;
377     }
378     else
379     {
380       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
381       desc = NULL;
382     }
383   }
384
385   port = 0;
386   if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
387   {
388     if (GNUNET_OK !=
389         GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
390                                                "PORT", &port))
391     {
392       LOG (GNUNET_ERROR_TYPE_ERROR,
393            _("Require valid port number for service `%s' in configuration!\n"),
394            service_name);
395     }
396     if (port > 65535)
397     {
398       LOG (GNUNET_ERROR_TYPE_ERROR,
399            _("Require valid port number for service `%s' in configuration!\n"),
400            service_name);
401       return GNUNET_SYSERR;
402     }
403   }
404
405   if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
406   {
407     GNUNET_break (GNUNET_OK ==
408                   GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
409                                                          "BINDTO", &hostname));
410   }
411   else
412     hostname = NULL;
413
414   unixpath = NULL;
415   abstract = GNUNET_NO;
416 #ifdef AF_UNIX
417   if ((GNUNET_YES ==
418        GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
419       (GNUNET_OK ==
420        GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
421                                               &unixpath)) &&
422       (0 < strlen (unixpath)))
423   {
424     /* probe UNIX support */
425     struct sockaddr_un s_un;
426
427     if (strlen (unixpath) >= sizeof (s_un.sun_path))
428     {
429       LOG (GNUNET_ERROR_TYPE_WARNING,
430            _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
431            (unsigned long long) sizeof (s_un.sun_path));
432       unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
433       LOG (GNUNET_ERROR_TYPE_INFO,
434            _("Using `%s' instead\n"),
435            unixpath);
436     }
437 #ifdef LINUX
438     abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
439                                                      "TESTING",
440                                                      "USE_ABSTRACT_SOCKETS");
441     if (GNUNET_SYSERR == abstract)
442       abstract = GNUNET_NO;
443 #endif
444     if ((GNUNET_YES != abstract)
445         && (GNUNET_OK !=
446             GNUNET_DISK_directory_create_for_file (unixpath)))
447       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
448                                 "mkdir",
449                                 unixpath);
450   }
451   if (NULL != unixpath)
452   {
453     desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
454     if (NULL == desc)
455     {
456       if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
457           (EACCES == errno))
458       {
459         LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
460         GNUNET_free_non_null (hostname);
461         GNUNET_free (unixpath);
462         return GNUNET_SYSERR;
463       }
464       LOG (GNUNET_ERROR_TYPE_INFO,
465            _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
466            service_name,
467            STRERROR (errno));
468       GNUNET_free (unixpath);
469       unixpath = NULL;
470     }
471     else
472     {
473       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
474       desc = NULL;
475     }
476   }
477 #endif
478
479   if ((0 == port) && (NULL == unixpath))
480   {
481     LOG (GNUNET_ERROR_TYPE_ERROR,
482          _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
483          service_name);
484     GNUNET_free_non_null (hostname);
485     return GNUNET_SYSERR;
486   }
487   if (0 == port)
488   {
489     saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
490     saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
491     add_unixpath (saddrs, saddrlens, unixpath, abstract);
492     GNUNET_free_non_null (unixpath);
493     GNUNET_free_non_null (hostname);
494     *addrs = saddrs;
495     *addr_lens = saddrlens;
496     return 1;
497   }
498
499   if (NULL != hostname)
500   {
501     LOG (GNUNET_ERROR_TYPE_DEBUG,
502          "Resolving `%s' since that is where `%s' will bind to.\n",
503          hostname,
504          service_name);
505     memset (&hints, 0, sizeof (struct addrinfo));
506     if (disablev6)
507       hints.ai_family = AF_INET;
508     hints.ai_protocol = IPPROTO_TCP;
509     if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
510         (NULL == res))
511     {
512       LOG (GNUNET_ERROR_TYPE_ERROR,
513            _("Failed to resolve `%s': %s\n"),
514            hostname,
515            gai_strerror (ret));
516       GNUNET_free (hostname);
517       GNUNET_free_non_null (unixpath);
518       return GNUNET_SYSERR;
519     }
520     next = res;
521     i = 0;
522     while (NULL != (pos = next))
523     {
524       next = pos->ai_next;
525       if ((disablev6) && (pos->ai_family == AF_INET6))
526         continue;
527       i++;
528     }
529     if (0 == i)
530     {
531       LOG (GNUNET_ERROR_TYPE_ERROR,
532            _("Failed to find %saddress for `%s'.\n"),
533            disablev6 ? "IPv4 " : "",
534            hostname);
535       freeaddrinfo (res);
536       GNUNET_free (hostname);
537       GNUNET_free_non_null (unixpath);
538       return GNUNET_SYSERR;
539     }
540     resi = i;
541     if (NULL != unixpath)
542       resi++;
543     saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
544     saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
545     i = 0;
546     if (NULL != unixpath)
547     {
548       add_unixpath (saddrs, saddrlens, unixpath, abstract);
549       i++;
550     }
551     next = res;
552     while (NULL != (pos = next))
553     {
554       next = pos->ai_next;
555       if ((disablev6) && (AF_INET6 == pos->ai_family))
556         continue;
557       if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
558         continue;               /* not TCP */
559       if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
560         continue;               /* huh? */
561       LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
562            service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
563       if (AF_INET == pos->ai_family)
564       {
565         GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
566         saddrlens[i] = pos->ai_addrlen;
567         saddrs[i] = GNUNET_malloc (saddrlens[i]);
568         GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
569         ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
570       }
571       else
572       {
573         GNUNET_assert (AF_INET6 == pos->ai_family);
574         GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
575         saddrlens[i] = pos->ai_addrlen;
576         saddrs[i] = GNUNET_malloc (saddrlens[i]);
577         GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
578         ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
579       }
580       i++;
581     }
582     GNUNET_free (hostname);
583     freeaddrinfo (res);
584     resi = i;
585   }
586   else
587   {
588     /* will bind against everything, just set port */
589     if (disablev6)
590     {
591       /* V4-only */
592       resi = 1;
593       if (NULL != unixpath)
594         resi++;
595       i = 0;
596       saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
597       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
598       if (NULL != unixpath)
599       {
600         add_unixpath (saddrs, saddrlens, unixpath, abstract);
601         i++;
602       }
603       saddrlens[i] = sizeof (struct sockaddr_in);
604       saddrs[i] = GNUNET_malloc (saddrlens[i]);
605 #if HAVE_SOCKADDR_IN_SIN_LEN
606       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
607 #endif
608       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
609       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
610     }
611     else
612     {
613       /* dual stack */
614       resi = 2;
615       if (NULL != unixpath)
616         resi++;
617       saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
618       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
619       i = 0;
620       if (NULL != unixpath)
621       {
622         add_unixpath (saddrs, saddrlens, unixpath, abstract);
623         i++;
624       }
625       saddrlens[i] = sizeof (struct sockaddr_in6);
626       saddrs[i] = GNUNET_malloc (saddrlens[i]);
627 #if HAVE_SOCKADDR_IN_SIN_LEN
628       ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
629 #endif
630       ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
631       ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
632       i++;
633       saddrlens[i] = sizeof (struct sockaddr_in);
634       saddrs[i] = GNUNET_malloc (saddrlens[i]);
635 #if HAVE_SOCKADDR_IN_SIN_LEN
636       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
637 #endif
638       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
639       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
640     }
641   }
642   GNUNET_free_non_null (unixpath);
643   *addrs = saddrs;
644   *addr_lens = saddrlens;
645   return resi;
646 }
647
648
649 /**
650  * Signal our client that we will start or stop the
651  * service.
652  *
653  * @param client who is being signalled
654  * @param name name of the service
655  * @param request_id id of the request that is being responded to.
656  * @param result message type to send
657  * @return NULL if it was not found
658  */
659 static void
660 signal_result (struct GNUNET_SERVICE_Client *client,
661                const char *name,
662                uint64_t request_id,
663                enum GNUNET_ARM_Result result)
664 {
665   struct GNUNET_MQ_Envelope *env;
666   struct GNUNET_ARM_ResultMessage *msg;
667
668   env = GNUNET_MQ_msg (msg,
669                        GNUNET_MESSAGE_TYPE_ARM_RESULT);
670   msg->result = htonl (result);
671   msg->arm_msg.request_id = GNUNET_htonll (request_id);
672   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
673                   env);
674 }
675
676
677 /**
678  * Tell all clients about status change of a service.
679  *
680  * @param name name of the service
681  * @param status message type to send
682  * @param unicast if not NULL, send to this client only.
683  *                otherwise, send to all clients in the notifier
684  */
685 static void
686 broadcast_status (const char *name,
687                   enum GNUNET_ARM_ServiceStatus status,
688                   struct GNUNET_SERVICE_Client *unicast)
689 {
690   struct GNUNET_MQ_Envelope *env;
691   struct GNUNET_ARM_StatusMessage *msg;
692   size_t namelen;
693
694   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
695               "Sending status %u of service `%s' to client\n",
696               (unsigned int) status,
697               name);
698   namelen = strlen (name) + 1;
699   env = GNUNET_MQ_msg_extra (msg,
700                              namelen,
701                              GNUNET_MESSAGE_TYPE_ARM_STATUS);
702   msg->status = htonl ((uint32_t) (status));
703   GNUNET_memcpy ((char *) &msg[1],
704                  name,
705                  namelen);
706   if (NULL == unicast)
707   {
708     if (NULL != notifier)
709       GNUNET_notification_context_broadcast (notifier,
710                                              &msg->header,
711                                              GNUNET_YES);
712     GNUNET_MQ_discard (env);
713   }
714   else
715   {
716     GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (unicast),
717                     env);
718   }
719 }
720
721
722 /**
723  * Actually start the process for the given service.
724  *
725  * @param sl identifies service to start
726  * @param client that asked to start the service (may be NULL)
727  * @param request_id id of the request in response to which the process is
728  *                   being started. 0 if starting was not requested.
729  */
730 static void
731 start_process (struct ServiceList *sl,
732                struct GNUNET_SERVICE_Client *client,
733                uint64_t request_id)
734 {
735   char *loprefix;
736   char *options;
737   int use_debug;
738   int is_simple_service;
739   struct ServiceListeningInfo *sli;
740   SOCKTYPE *lsocks;
741   unsigned int ls;
742   char *binary;
743   char *quotedbinary;
744
745   /* calculate listen socket list */
746   lsocks = NULL;
747   ls = 0;
748   for (sli = sl->listen_head; NULL != sli; sli = sli->next)
749     {
750       GNUNET_array_append (lsocks, ls,
751                            GNUNET_NETWORK_get_fd (sli->listen_socket));
752       if (NULL != sli->accept_task)
753         {
754           GNUNET_SCHEDULER_cancel (sli->accept_task);
755           sli->accept_task = NULL;
756         }
757     }
758 #if WINDOWS
759   GNUNET_array_append (lsocks,
760                        ls,
761                        INVALID_SOCKET);
762 #else
763   GNUNET_array_append (lsocks,
764                        ls,
765                        -1);
766 #endif
767
768   /* obtain configuration */
769   if (GNUNET_OK !=
770       GNUNET_CONFIGURATION_get_value_string (cfg,
771                                              sl->name,
772                                              "PREFIX",
773                                              &loprefix))
774     loprefix = GNUNET_strdup (prefix_command);
775   else
776     loprefix = GNUNET_CONFIGURATION_expand_dollar (cfg,
777                                                    loprefix);
778   if (GNUNET_OK !=
779       GNUNET_CONFIGURATION_get_value_string (cfg,
780                                              sl->name,
781                                              "OPTIONS",
782                                              &options))
783     options = NULL;
784   else
785     options = GNUNET_CONFIGURATION_expand_dollar (cfg,
786                                                   options);
787   {
788     char *new_options;
789     char *optpos;
790     char *fin_options;
791
792     fin_options = GNUNET_strdup (final_option);
793     /* replace '{}' with service name */
794     while (NULL != (optpos = strstr (fin_options,
795                                      "{}")))
796     {
797       /* terminate string at opening parenthesis */
798       *optpos = 0;
799       GNUNET_asprintf (&new_options,
800                        "%s%s%s",
801                        fin_options,
802                        sl->name,
803                        optpos + 2);
804       GNUNET_free (fin_options);
805       fin_options = new_options;
806     }
807     if (NULL != options)
808     {
809       /* combine "fin_options" with "options" */
810       optpos = options;
811       GNUNET_asprintf (&options,
812                        "%s %s",
813                        fin_options,
814                        optpos);
815       GNUNET_free (fin_options);
816       GNUNET_free (optpos);
817     }
818     else
819     {
820       /* only have "fin_options", use that */
821       options = fin_options;
822     }
823   }
824   options = GNUNET_CONFIGURATION_expand_dollar (cfg,
825                                                 options);
826   use_debug = GNUNET_CONFIGURATION_get_value_yesno (cfg,
827                                                     sl->name,
828                                                     "DEBUG");
829   {
830     const char *service_type = NULL;
831     const char *choices[] = { "GNUNET", "SIMPLE", NULL };
832
833     is_simple_service = GNUNET_NO;
834     if ( (GNUNET_OK ==
835           GNUNET_CONFIGURATION_get_value_choice (cfg,
836                                                  sl->name,
837                                                  "TYPE",
838                                                  choices,
839                                                  &service_type)) &&
840          (0 == strcasecmp (service_type, "SIMPLE")) )
841       is_simple_service = GNUNET_YES;
842   }
843
844   GNUNET_assert (NULL == sl->proc);
845   if (GNUNET_YES == is_simple_service)
846   {
847     /* A simple service will receive no GNUnet specific
848        command line options. */
849     binary = GNUNET_strdup (sl->binary);
850     binary = GNUNET_CONFIGURATION_expand_dollar (cfg, binary);
851     GNUNET_asprintf (&quotedbinary,
852                      "\"%s\"",
853                      sl->binary);
854     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
855                 "Starting simple service `%s' using binary `%s'\n",
856                 sl->name, sl->binary);
857     /* FIXME: dollar expansion should only be done outside
858      * of ''-quoted strings, escaping should be considered. */
859     if (NULL != options)
860       options = GNUNET_CONFIGURATION_expand_dollar (cfg, options);
861     sl->proc =
862       GNUNET_OS_start_process_s (sl->pipe_control,
863                                  GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
864                                  lsocks,
865                                  loprefix,
866                                  quotedbinary,
867                                  options,
868                                  NULL);
869   }
870   else
871   {
872     /* actually start process */
873     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
874                 "Starting service `%s' using binary `%s' and configuration `%s'\n",
875                 sl->name, sl->binary, sl->config);
876     binary = GNUNET_OS_get_libexec_binary_path (sl->binary);
877     GNUNET_asprintf (&quotedbinary,
878                      "\"%s\"",
879                      binary);
880
881     if (GNUNET_YES == use_debug)
882     {
883       if (NULL == sl->config)
884         sl->proc =
885           GNUNET_OS_start_process_s (sl->pipe_control,
886                                      GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
887                                      lsocks,
888                                      loprefix,
889                                      quotedbinary,
890                                      "-L", "DEBUG",
891                                      options,
892                                      NULL);
893       else
894         sl->proc =
895             GNUNET_OS_start_process_s (sl->pipe_control,
896                                        GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
897                                        lsocks,
898                                        loprefix,
899                                        quotedbinary,
900                                        "-c", sl->config,
901                                        "-L", "DEBUG",
902                                        options,
903                                        NULL);
904     }
905     else
906     {
907       if (NULL == sl->config)
908         sl->proc =
909             GNUNET_OS_start_process_s (sl->pipe_control,
910                                        GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
911                                        lsocks,
912                                        loprefix,
913                                        quotedbinary,
914                                        options,
915                                        NULL);
916       else
917         sl->proc =
918             GNUNET_OS_start_process_s (sl->pipe_control,
919                                        GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
920                                        lsocks,
921                                        loprefix,
922                                        quotedbinary,
923                                        "-c", sl->config,
924                                        options,
925                                        NULL);
926     }
927   }
928   GNUNET_free (binary);
929   GNUNET_free (quotedbinary);
930   if (NULL == sl->proc)
931   {
932     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
933                 _("Failed to start service `%s'\n"),
934                 sl->name);
935     if (client)
936       signal_result (client,
937                      sl->name,
938                      request_id,
939                      GNUNET_ARM_RESULT_START_FAILED);
940   }
941   else
942   {
943     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
944                 _("Starting service `%s'\n"),
945                 sl->name);
946     broadcast_status (sl->name,
947                       GNUNET_ARM_SERVICE_STARTING,
948                       NULL);
949     if (client)
950       signal_result (client,
951                      sl->name,
952                      request_id,
953                      GNUNET_ARM_RESULT_STARTING);
954   }
955   /* clean up */
956   GNUNET_free (loprefix);
957   GNUNET_free (options);
958   GNUNET_array_grow (lsocks,
959                      ls,
960                      0);
961 }
962
963
964 /**
965  * Find the process with the given service
966  * name in the given list and return it.
967  *
968  * @param name which service entry to look up
969  * @return NULL if it was not found
970  */
971 static struct ServiceList *
972 find_service (const char *name)
973 {
974   struct ServiceList *sl;
975
976   sl = running_head;
977   while (sl != NULL)
978     {
979       if (0 == strcasecmp (sl->name, name))
980         return sl;
981       sl = sl->next;
982     }
983   return NULL;
984 }
985
986
987 /**
988  * First connection has come to the listening socket associated with the service,
989  * create the service in order to relay the incoming connection to it
990  *
991  * @param cls callback data, `struct ServiceListeningInfo` describing a listen socket
992  */
993 static void
994 accept_connection (void *cls)
995 {
996   struct ServiceListeningInfo *sli = cls;
997   struct ServiceList *sl = sli->sl;
998
999   sli->accept_task = NULL;
1000   GNUNET_assert (GNUNET_NO == in_shutdown);
1001   start_process (sl, NULL, 0);
1002 }
1003
1004
1005 /**
1006  * Creating a listening socket for each of the service's addresses and
1007  * wait for the first incoming connection to it
1008  *
1009  * @param sa address associated with the service
1010  * @param addr_len length of @a sa
1011  * @param sl service entry for the service in question
1012  */
1013 static void
1014 create_listen_socket (struct sockaddr *sa,
1015                       socklen_t addr_len,
1016                       struct ServiceList *sl)
1017 {
1018   static int on = 1;
1019   struct GNUNET_NETWORK_Handle *sock;
1020   struct ServiceListeningInfo *sli;
1021 #ifndef WINDOWS
1022   int match_uid;
1023   int match_gid;
1024 #endif
1025
1026   switch (sa->sa_family)
1027   {
1028   case AF_INET:
1029     sock = GNUNET_NETWORK_socket_create (PF_INET,
1030                                          SOCK_STREAM,
1031                                          0);
1032     break;
1033   case AF_INET6:
1034     sock = GNUNET_NETWORK_socket_create (PF_INET6,
1035                                          SOCK_STREAM,
1036                                          0);
1037     break;
1038   case AF_UNIX:
1039     if (0 == strcmp (GNUNET_a2s (sa,
1040                                  addr_len),
1041                      "@"))      /* Do not bind to blank UNIX path! */
1042       return;
1043     sock = GNUNET_NETWORK_socket_create (PF_UNIX,
1044                                          SOCK_STREAM,
1045                                          0);
1046     break;
1047   default:
1048     GNUNET_break (0);
1049     sock = NULL;
1050     errno = EAFNOSUPPORT;
1051     break;
1052   }
1053   if (NULL == sock)
1054   {
1055     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1056                 _("Unable to create socket for service `%s': %s\n"),
1057                 sl->name,
1058                 STRERROR (errno));
1059     GNUNET_free (sa);
1060     return;
1061   }
1062   if (GNUNET_OK !=
1063       GNUNET_NETWORK_socket_setsockopt (sock,
1064                                         SOL_SOCKET,
1065                                         SO_REUSEADDR,
1066                                         &on,
1067                                         sizeof (on)))
1068     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1069                          "setsockopt");
1070 #ifdef IPV6_V6ONLY
1071   if ( (sa->sa_family == AF_INET6) &&
1072        (GNUNET_OK !=
1073         GNUNET_NETWORK_socket_setsockopt (sock,
1074                                           IPPROTO_IPV6,
1075                                           IPV6_V6ONLY,
1076                                           &on,
1077                                           sizeof (on))) )
1078     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1079                          "setsockopt");
1080 #endif
1081 #ifndef WINDOWS
1082   if (AF_UNIX == sa->sa_family)
1083     GNUNET_NETWORK_unix_precheck ((struct sockaddr_un *) sa);
1084 #endif
1085   if (GNUNET_OK !=
1086       GNUNET_NETWORK_socket_bind (sock,
1087                                   (const struct sockaddr *) sa,
1088                                   addr_len))
1089   {
1090     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1091                 _("Unable to bind listening socket for service `%s' to address `%s': %s\n"),
1092                 sl->name,
1093                 GNUNET_a2s (sa,
1094                             addr_len),
1095                 STRERROR (errno));
1096     GNUNET_break (GNUNET_OK ==
1097                   GNUNET_NETWORK_socket_close (sock));
1098     GNUNET_free (sa);
1099     return;
1100   }
1101 #ifndef WINDOWS
1102   if ((AF_UNIX == sa->sa_family)
1103 #ifdef LINUX
1104       /* Permission settings are not required when abstract sockets are used */
1105       && ('\0' != ((const struct sockaddr_un *)sa)->sun_path[0])
1106 #endif
1107       )
1108   {
1109     match_uid =
1110       GNUNET_CONFIGURATION_get_value_yesno (cfg,
1111                                             sl->name,
1112                                             "UNIX_MATCH_UID");
1113     match_gid =
1114       GNUNET_CONFIGURATION_get_value_yesno (cfg,
1115                                             sl->name,
1116                                             "UNIX_MATCH_GID");
1117     GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sa)->sun_path,
1118                                  match_uid,
1119                                  match_gid);
1120
1121   }
1122 #endif
1123   if (GNUNET_OK !=
1124       GNUNET_NETWORK_socket_listen (sock, 5))
1125   {
1126     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1127                          "listen");
1128     GNUNET_break (GNUNET_OK ==
1129                   GNUNET_NETWORK_socket_close (sock));
1130     GNUNET_free (sa);
1131     return;
1132   }
1133   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1134               _("ARM now monitors connections to service `%s' at `%s'\n"),
1135               sl->name,
1136               GNUNET_a2s (sa,
1137                           addr_len));
1138   sli = GNUNET_new (struct ServiceListeningInfo);
1139   sli->service_addr = sa;
1140   sli->service_addr_len = addr_len;
1141   sli->listen_socket = sock;
1142   sli->sl = sl;
1143   sli->accept_task
1144     = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1145                                      sock,
1146                                      &accept_connection, sli);
1147   GNUNET_CONTAINER_DLL_insert (sl->listen_head,
1148                                sl->listen_tail,
1149                                sli);
1150 }
1151
1152
1153 /**
1154  * Remove and free an entry in the service list.  Listen sockets
1155  * must have already been cleaned up.  Only to be called during shutdown.
1156  *
1157  * @param sl entry to free
1158  */
1159 static void
1160 free_service (struct ServiceList *sl)
1161 {
1162   GNUNET_assert (GNUNET_YES == in_shutdown);
1163   GNUNET_CONTAINER_DLL_remove (running_head,
1164                                running_tail,
1165                                sl);
1166   GNUNET_assert (NULL == sl->listen_head);
1167   GNUNET_free_non_null (sl->config);
1168   GNUNET_free_non_null (sl->binary);
1169   GNUNET_free (sl->name);
1170   GNUNET_free (sl);
1171 }
1172
1173
1174 /**
1175  * Check START-message.
1176  *
1177  * @param cls identification of the client
1178  * @param amsg the actual message
1179  * @return #GNUNET_OK to keep the connection open,
1180  *         #GNUNET_SYSERR to close it (signal serious error)
1181  */
1182 static int
1183 check_start (void *cls,
1184              const struct GNUNET_ARM_Message *amsg)
1185 {
1186   uint16_t size;
1187   const char *servicename;
1188
1189   size = ntohs (amsg->header.size) - sizeof (struct GNUNET_ARM_Message);
1190   servicename = (const char *) &amsg[1];
1191   if ( (0 == size) ||
1192        (servicename[size - 1] != '\0') )
1193   {
1194     GNUNET_break (0);
1195     return GNUNET_SYSERR;
1196   }
1197   return GNUNET_OK;
1198 }
1199
1200
1201 /**
1202  * Handle START-message.
1203  *
1204  * @param cls identification of the client
1205  * @param amsg the actual message
1206  */
1207 static void
1208 handle_start (void *cls,
1209               const struct GNUNET_ARM_Message *amsg)
1210 {
1211   struct GNUNET_SERVICE_Client *client = cls;
1212   const char *servicename;
1213   struct ServiceList *sl;
1214   uint64_t request_id;
1215
1216   request_id = GNUNET_ntohll (amsg->request_id);
1217   servicename = (const char *) &amsg[1];
1218   GNUNET_SERVICE_client_continue (client);
1219   if (GNUNET_YES == in_shutdown)
1220   {
1221     signal_result (client,
1222                    servicename,
1223                    request_id,
1224                    GNUNET_ARM_RESULT_IN_SHUTDOWN);
1225     return;
1226   }
1227   sl = find_service (servicename);
1228   if (NULL == sl)
1229   {
1230     signal_result (client,
1231                    servicename,
1232                    request_id,
1233                    GNUNET_ARM_RESULT_IS_NOT_KNOWN);
1234     return;
1235   }
1236   sl->force_start = GNUNET_YES;
1237   if (NULL != sl->proc)
1238   {
1239     signal_result (client,
1240                    servicename,
1241                    request_id,
1242                    GNUNET_ARM_RESULT_IS_STARTED_ALREADY);
1243     return;
1244   }
1245   start_process (sl,
1246                  client,
1247                  request_id);
1248 }
1249
1250
1251 /**
1252  * Start a shutdown sequence.
1253  *
1254  * @param cls closure (refers to service)
1255  */
1256 static void
1257 trigger_shutdown (void *cls)
1258 {
1259   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1260               "Triggering shutdown\n");
1261   GNUNET_SCHEDULER_shutdown ();
1262 }
1263
1264
1265 /**
1266  * Check STOP-message.
1267  *
1268  * @param cls identification of the client
1269  * @param amsg the actual message
1270  * @return #GNUNET_OK to keep the connection open,
1271  *         #GNUNET_SYSERR to close it (signal serious error)
1272  */
1273 static int
1274 check_stop (void *cls,
1275             const struct GNUNET_ARM_Message *amsg)
1276 {
1277   uint16_t size;
1278   const char *servicename;
1279
1280   size = ntohs (amsg->header.size) - sizeof (struct GNUNET_ARM_Message);
1281   servicename = (const char *) &amsg[1];
1282   if ( (0 == size) ||
1283        (servicename[size - 1] != '\0') )
1284   {
1285     GNUNET_break (0);
1286     return GNUNET_SYSERR;
1287   }
1288   return GNUNET_OK;
1289 }
1290
1291
1292 /**
1293  * Handle STOP-message.
1294  *
1295  * @param cls identification of the client
1296  * @param amsg the actual message
1297  */
1298 static void
1299 handle_stop (void *cls,
1300              const struct GNUNET_ARM_Message *amsg)
1301 {
1302   struct GNUNET_SERVICE_Client *client = cls;
1303   struct ServiceList *sl;
1304   const char *servicename;
1305   uint64_t request_id;
1306
1307   request_id = GNUNET_ntohll (amsg->request_id);
1308   servicename = (const char *) &amsg[1];
1309   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1310               _("Preparing to stop `%s'\n"),
1311               servicename);
1312   GNUNET_SERVICE_client_continue (client);
1313   if (0 == strcasecmp (servicename,
1314                        "arm"))
1315   {
1316     broadcast_status (servicename,
1317                       GNUNET_ARM_SERVICE_STOPPING,
1318                       NULL);
1319     signal_result (client,
1320                    servicename,
1321                    request_id,
1322                    GNUNET_ARM_RESULT_STOPPING);
1323     GNUNET_SERVICE_client_persist (client);
1324     GNUNET_SCHEDULER_add_now (&trigger_shutdown,
1325                               NULL);
1326     return;
1327   }
1328   sl = find_service (servicename);
1329   if (NULL == sl)
1330   {
1331     signal_result (client,
1332                    servicename,
1333                    request_id,
1334                    GNUNET_ARM_RESULT_IS_NOT_KNOWN);
1335     return;
1336   }
1337   sl->force_start = GNUNET_NO;
1338   if (GNUNET_YES == in_shutdown)
1339   {
1340     /* shutdown in progress */
1341     signal_result (client,
1342                    servicename,
1343                    request_id,
1344                    GNUNET_ARM_RESULT_IN_SHUTDOWN);
1345     return;
1346   }
1347   if (NULL != sl->killing_client)
1348   {
1349     /* killing already in progress */
1350     signal_result (client,
1351                    servicename,
1352                    request_id,
1353                    GNUNET_ARM_RESULT_IS_STOPPING_ALREADY);
1354     return;
1355   }
1356   if (NULL == sl->proc)
1357   {
1358     /* process is down */
1359     signal_result (client,
1360                    servicename,
1361                    request_id,
1362                    GNUNET_ARM_RESULT_IS_STOPPED_ALREADY);
1363     return;
1364   }
1365   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1366               "Sending kill signal to service `%s', waiting for process to die.\n",
1367               servicename);
1368   broadcast_status (servicename,
1369                     GNUNET_ARM_SERVICE_STOPPING,
1370                     NULL);
1371   /* no signal_start - only when it's STOPPED */
1372   sl->killed_at = GNUNET_TIME_absolute_get ();
1373   if (0 != GNUNET_OS_process_kill (sl->proc,
1374                                    GNUNET_TERM_SIG))
1375     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1376                          "kill");
1377   sl->killing_client = client;
1378   sl->killing_client_request_id = request_id;
1379 }
1380
1381
1382 /**
1383  * Handle LIST-message.
1384  *
1385  * @param cls identification of the client
1386  * @param message the actual message
1387  */
1388 static void
1389 handle_list (void *cls,
1390              const struct GNUNET_ARM_Message *request)
1391 {
1392   struct GNUNET_SERVICE_Client *client = cls;
1393   struct GNUNET_MQ_Envelope *env;
1394   struct GNUNET_ARM_ListResultMessage *msg;
1395   size_t string_list_size;
1396   struct ServiceList *sl;
1397   uint16_t count;
1398   char *pos;
1399
1400   GNUNET_break (0 == ntohl (request->reserved));
1401   count = 0;
1402   string_list_size = 0;
1403
1404   /* first count the running processes get their name's size */
1405   for (sl = running_head; NULL != sl; sl = sl->next)
1406   {
1407     if (NULL != sl->proc)
1408     {
1409       string_list_size += strlen (sl->name);
1410       string_list_size += strlen (sl->binary);
1411       string_list_size += 4;
1412       count++;
1413     }
1414   }
1415
1416   env = GNUNET_MQ_msg_extra (msg,
1417                              string_list_size,
1418                              GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT);
1419   msg->arm_msg.request_id = request->request_id;
1420   msg->count = htons (count);
1421
1422   pos = (char *) &msg[1];
1423   for (sl = running_head; NULL != sl; sl = sl->next)
1424   {
1425     if (NULL != sl->proc)
1426     {
1427       size_t s = strlen (sl->name) + strlen (sl->binary) + 4;
1428       GNUNET_snprintf (pos,
1429                        s,
1430                        "%s (%s)",
1431                        sl->name,
1432                        sl->binary);
1433       pos += s;
1434     }
1435   }
1436   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
1437                   env);
1438   GNUNET_SERVICE_client_continue (client);
1439 }
1440
1441
1442 /**
1443  * Handle TEST-message by sending back TEST.
1444  *
1445  * @param cls identification of the client
1446  * @param message the actual message
1447  */
1448 static void
1449 handle_test (void *cls,
1450              const struct GNUNET_MessageHeader *message)
1451 {
1452   struct GNUNET_SERVICE_Client *client = cls;
1453   struct GNUNET_MQ_Envelope *env;
1454   struct GNUNET_MessageHeader *msg;
1455
1456   env = GNUNET_MQ_msg (msg,
1457                        GNUNET_MESSAGE_TYPE_ARM_TEST);
1458   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
1459                   env);
1460   GNUNET_SERVICE_client_continue (client);
1461 }
1462
1463
1464 /**
1465  * We are done with everything.  Stop remaining
1466  * tasks, signal handler and the server.
1467  */
1468 static void
1469 do_shutdown ()
1470 {
1471   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1472               "Last shutdown phase\n");
1473   if (NULL != notifier)
1474   {
1475     GNUNET_notification_context_destroy (notifier);
1476     notifier = NULL;
1477   }
1478   if (NULL != service)
1479   {
1480     GNUNET_SERVICE_shutdown (service);
1481     service = NULL;
1482   }
1483   if (NULL != child_death_task)
1484   {
1485     GNUNET_SCHEDULER_cancel (child_death_task);
1486     child_death_task = NULL;
1487   }
1488 }
1489
1490
1491 /**
1492  * Count how many services are still active.
1493  *
1494  * @param running_head list of services
1495  * @return number of active services found
1496  */
1497 static unsigned int
1498 list_count (struct ServiceList *running_head)
1499 {
1500   struct ServiceList *i;
1501   unsigned int res;
1502
1503   for (res = 0, i = running_head; i; i = i->next, res++)
1504     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1505                 "%s\n",
1506                 i->name);
1507   return res;
1508 }
1509
1510
1511 /**
1512  * Task run for shutdown.
1513  *
1514  * @param cls closure, NULL if we need to self-restart
1515  */
1516 static void
1517 shutdown_task (void *cls)
1518 {
1519   struct ServiceList *pos;
1520   struct ServiceList *nxt;
1521   struct ServiceListeningInfo *sli;
1522
1523   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1524               "First shutdown phase\n");
1525   if (NULL != child_restart_task)
1526   {
1527     GNUNET_SCHEDULER_cancel (child_restart_task);
1528     child_restart_task = NULL;
1529   }
1530   in_shutdown = GNUNET_YES;
1531   /* first, stop listening */
1532   for (pos = running_head; NULL != pos; pos = pos->next)
1533   {
1534     while (NULL != (sli = pos->listen_head))
1535     {
1536       GNUNET_CONTAINER_DLL_remove (pos->listen_head,
1537                                    pos->listen_tail,
1538                                    sli);
1539       if (NULL != sli->accept_task)
1540       {
1541         GNUNET_SCHEDULER_cancel (sli->accept_task);
1542         sli->accept_task = NULL;
1543       }
1544       GNUNET_break (GNUNET_OK ==
1545                     GNUNET_NETWORK_socket_close (sli->listen_socket));
1546       GNUNET_free (sli->service_addr);
1547       GNUNET_free (sli);
1548     }
1549   }
1550   /* then, shutdown all existing service processes */
1551   nxt = running_head;
1552   while (NULL != (pos = nxt))
1553   {
1554     nxt = pos->next;
1555     if (NULL != pos->proc)
1556     {
1557       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1558                   "Stopping service `%s'\n",
1559                   pos->name);
1560       pos->killed_at = GNUNET_TIME_absolute_get ();
1561       if (0 != GNUNET_OS_process_kill (pos->proc,
1562                                        GNUNET_TERM_SIG))
1563         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1564                              "kill");
1565     }
1566     else
1567     {
1568       free_service (pos);
1569     }
1570   }
1571   /* finally, should all service processes be already gone, terminate for real */
1572   if (NULL == running_head)
1573     do_shutdown ();
1574   else
1575     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1576                 "Delaying shutdown, have %u childs still running\n",
1577                 list_count (running_head));
1578 }
1579
1580
1581 /**
1582  * Task run whenever it is time to restart a child that died.
1583  *
1584  * @param cls closure, always NULL
1585  */
1586 static void
1587 delayed_restart_task (void *cls)
1588
1589 {
1590   struct ServiceList *sl;
1591   struct GNUNET_TIME_Relative lowestRestartDelay;
1592   struct ServiceListeningInfo *sli;
1593
1594   child_restart_task = NULL;
1595   GNUNET_assert (GNUNET_NO == in_shutdown);
1596   lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL;
1597
1598   /* check for services that need to be restarted due to
1599    * configuration changes or because the last restart failed */
1600   for (sl = running_head; NULL != sl; sl = sl->next)
1601   {
1602     if (NULL != sl->proc)
1603       continue;
1604     /* service is currently not running */
1605     if (0 == GNUNET_TIME_absolute_get_remaining (sl->restart_at).rel_value_us)
1606     {
1607       /* restart is now allowed */
1608       if (sl->force_start)
1609       {
1610         /* process should run by default, start immediately */
1611         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1612                     _("Restarting service `%s'.\n"),
1613                     sl->name);
1614         start_process (sl,
1615                        NULL,
1616                        0);
1617       }
1618       else
1619       {
1620         /* process is run on-demand, ensure it is re-started if there is demand */
1621         for (sli = sl->listen_head; NULL != sli; sli = sli->next)
1622           if (NULL == sli->accept_task)
1623           {
1624             /* accept was actually paused, so start it again */
1625             sli->accept_task
1626               = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1627                                                sli->listen_socket,
1628                                                &accept_connection,
1629                                                sli);
1630           }
1631       }
1632     }
1633     else
1634     {
1635       /* update calculation for earliest time to reactivate a service */
1636       lowestRestartDelay =
1637         GNUNET_TIME_relative_min (lowestRestartDelay,
1638                                   GNUNET_TIME_absolute_get_remaining
1639                                   (sl->restart_at));
1640     }
1641   }
1642   if (lowestRestartDelay.rel_value_us != GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1643   {
1644     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1645                 "Will restart process in %s\n",
1646                 GNUNET_STRINGS_relative_time_to_string (lowestRestartDelay,
1647                                                         GNUNET_YES));
1648     child_restart_task =
1649       GNUNET_SCHEDULER_add_delayed_with_priority (lowestRestartDelay,
1650                                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
1651                                                   &delayed_restart_task,
1652                                                   NULL);
1653   }
1654 }
1655
1656
1657 /**
1658  * Task triggered whenever we receive a SIGCHLD (child
1659  * process died).
1660  *
1661  * @param cls closure, NULL if we need to self-restart
1662  */
1663 static void
1664 maint_child_death (void *cls)
1665 {
1666   struct ServiceList *pos;
1667   struct ServiceList *next;
1668   struct ServiceListeningInfo *sli;
1669   const char *statstr;
1670   int statcode;
1671   int ret;
1672   char c[16];
1673   enum GNUNET_OS_ProcessStatusType statusType;
1674   unsigned long statusCode;
1675   const struct GNUNET_DISK_FileHandle *pr;
1676
1677   pr = GNUNET_DISK_pipe_handle (sigpipe,
1678                                 GNUNET_DISK_PIPE_END_READ);
1679   child_death_task = NULL;
1680   /* consume the signal */
1681   GNUNET_break (0 < GNUNET_DISK_file_read (pr,
1682                                            &c,
1683                                            sizeof (c)));
1684
1685   /* check for services that died (WAITPID) */
1686   next = running_head;
1687   while (NULL != (pos = next))
1688   {
1689     next = pos->next;
1690
1691     if (NULL == pos->proc)
1692     {
1693       if (GNUNET_YES == in_shutdown)
1694         free_service (pos);
1695       continue;
1696     }
1697 #if HAVE_WAIT4
1698     if (NULL != wait_file)
1699     {
1700       /* need to use 'wait4()' to obtain and log performance data */
1701       struct rusage ru;
1702       int status;
1703       pid_t pid;
1704
1705       pid = GNUNET_OS_process_get_pid (pos->proc);
1706       ret = wait4 (pid,
1707                    &status,
1708                    WNOHANG,
1709                    &ru);
1710       if (ret <= 0)
1711         continue; /* no process done */
1712       if (WIFEXITED (status))
1713       {
1714         statusType = GNUNET_OS_PROCESS_EXITED;
1715         statusCode = WEXITSTATUS (status);
1716       }
1717       else if (WIFSIGNALED (status))
1718       {
1719         statusType = GNUNET_OS_PROCESS_SIGNALED;
1720         statusCode = WTERMSIG (status);
1721       }
1722       else if (WIFSTOPPED (status))
1723       {
1724         statusType = GNUNET_OS_PROCESS_SIGNALED;
1725         statusCode = WSTOPSIG (status);
1726       }
1727 #ifdef WIFCONTINUED
1728       else if (WIFCONTINUED (status))
1729       {
1730         statusType = GNUNET_OS_PROCESS_RUNNING;
1731         statusCode = 0;
1732       }
1733 #endif
1734       else
1735       {
1736         statusType = GNUNET_OS_PROCESS_UNKNOWN;
1737         statusCode = 0;
1738       }
1739       if ( (GNUNET_OS_PROCESS_EXITED == statusType) ||
1740            (GNUNET_OS_PROCESS_SIGNALED == statusType) )
1741       {
1742         double utime = ru.ru_utime.tv_sec + (ru.ru_utime.tv_usec / 10e6);
1743         double stime = ru.ru_stime.tv_sec + (ru.ru_stime.tv_usec / 10e6);
1744         fprintf (wait_file,
1745                  "%s(%u) %.3f %.3f %llu %llu %llu %llu %llu\n",
1746                  pos->binary,
1747                  (unsigned int) pid,
1748                  utime,
1749                  stime,
1750                  (unsigned long long) ru.ru_maxrss,
1751                  (unsigned long long) ru.ru_inblock,
1752                  (unsigned long long) ru.ru_oublock,
1753                  (unsigned long long) ru.ru_nvcsw,
1754                  (unsigned long long) ru.ru_nivcsw);
1755       }
1756     }
1757     else /* continue with JUST this "if" as "else" (intentionally no brackets!) */
1758 #endif
1759     if ( (GNUNET_SYSERR ==
1760           (ret =
1761            GNUNET_OS_process_status (pos->proc,
1762                                      &statusType,
1763                                      &statusCode))) ||
1764          (ret == GNUNET_NO) ||
1765          (statusType == GNUNET_OS_PROCESS_STOPPED) ||
1766          (statusType == GNUNET_OS_PROCESS_UNKNOWN) ||
1767          (statusType == GNUNET_OS_PROCESS_RUNNING) )
1768       continue;
1769
1770     if (statusType == GNUNET_OS_PROCESS_EXITED)
1771     {
1772       statstr = _( /* process termination method */ "exit");
1773       statcode = statusCode;
1774     }
1775     else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
1776     {
1777       statstr = _( /* process termination method */ "signal");
1778       statcode = statusCode;
1779     }
1780     else
1781     {
1782       statstr = _( /* process termination method */ "unknown");
1783       statcode = 0;
1784     }
1785     if (0 != pos->killed_at.abs_value_us)
1786     {
1787       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1788                   _("Service `%s' took %s to terminate\n"),
1789                   pos->name,
1790                   GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->killed_at),
1791                                                           GNUNET_YES));
1792     }
1793     GNUNET_OS_process_destroy (pos->proc);
1794     pos->proc = NULL;
1795     broadcast_status (pos->name,
1796                       GNUNET_ARM_SERVICE_STOPPED,
1797                       NULL);
1798     if (NULL != pos->killing_client)
1799     {
1800       signal_result (pos->killing_client, pos->name,
1801                      pos->killing_client_request_id,
1802                      GNUNET_ARM_RESULT_STOPPED);
1803       pos->killing_client = NULL;
1804       pos->killing_client_request_id = 0;
1805     }
1806     if (GNUNET_YES != in_shutdown)
1807     {
1808       if ( (statusType == GNUNET_OS_PROCESS_EXITED) &&
1809            (statcode == 0) )
1810       {
1811         /* process terminated normally, allow restart at any time */
1812         pos->restart_at.abs_value_us = 0;
1813         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1814                     _("Service `%s' terminated normally, will restart at any time\n"),
1815                     pos->name);
1816         /* process can still be re-started on-demand, ensure it is re-started if there is demand */
1817         for (sli = pos->listen_head; NULL != sli; sli = sli->next)
1818         {
1819           GNUNET_break (NULL == sli->accept_task);
1820           sli->accept_task =
1821             GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1822                                            sli->listen_socket,
1823                                            &accept_connection,
1824                                            sli);
1825         }
1826       }
1827       else
1828       {
1829         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1830                     _("Service `%s' terminated with status %s/%d, will restart in %s\n"),
1831                     pos->name,
1832                     statstr,
1833                     statcode,
1834                     GNUNET_STRINGS_relative_time_to_string (pos->backoff,
1835                                                             GNUNET_YES));
1836         {
1837           /* Reduce backoff based on runtime of the process,
1838              so that there is a cool-down if a process actually
1839              runs for a while. */
1840           struct GNUNET_TIME_Relative runtime;
1841           unsigned int minutes;
1842
1843           runtime = GNUNET_TIME_absolute_get_duration (pos->restart_at);
1844           minutes = runtime.rel_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us;
1845           if (minutes > 31)
1846             pos->backoff = GNUNET_TIME_UNIT_ZERO;
1847           else
1848             pos->backoff.rel_value_us <<= minutes;
1849         }
1850         /* schedule restart */
1851         pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff);
1852         pos->backoff = GNUNET_TIME_STD_BACKOFF (pos->backoff);
1853         if (NULL != child_restart_task)
1854           GNUNET_SCHEDULER_cancel (child_restart_task);
1855         child_restart_task
1856           = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
1857                                                 &delayed_restart_task,
1858                                                 NULL);
1859       }
1860     }
1861     else
1862     {
1863       free_service (pos);
1864     }
1865   }
1866   child_death_task = GNUNET_SCHEDULER_add_read_file (
1867       GNUNET_TIME_UNIT_FOREVER_REL,
1868       pr,
1869       &maint_child_death, NULL);
1870   if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
1871     do_shutdown ();
1872   else if (GNUNET_YES == in_shutdown)
1873     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1874         "Delaying shutdown after child's death, still have %u children\n",
1875         list_count (running_head));
1876
1877 }
1878
1879
1880 /**
1881  * Signal handler called for SIGCHLD.  Triggers the
1882  * respective handler by writing to the trigger pipe.
1883  */
1884 static void
1885 sighandler_child_death ()
1886 {
1887   static char c;
1888   int old_errno = errno;        /* back-up errno */
1889
1890   GNUNET_break (1 ==
1891                 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (sigpipe,
1892                                                                  GNUNET_DISK_PIPE_END_WRITE),
1893                                         &c,
1894                                         sizeof (c)));
1895   errno = old_errno;            /* restore errno */
1896 }
1897
1898
1899 /**
1900  * Setup our service record for the given section in the configuration file
1901  * (assuming the section is for a service).
1902  *
1903  * @param cls unused
1904  * @param section a section in the configuration file
1905  * @return #GNUNET_OK (continue)
1906  */
1907 static void
1908 setup_service (void *cls,
1909                const char *section)
1910 {
1911   struct ServiceList *sl;
1912   char *binary;
1913   char *config;
1914   struct stat sbuf;
1915   struct sockaddr **addrs;
1916   socklen_t *addr_lens;
1917   int ret;
1918   unsigned int i;
1919
1920   if (0 == strcasecmp (section,
1921                        "arm"))
1922     return;
1923   if (GNUNET_OK !=
1924       GNUNET_CONFIGURATION_get_value_string (cfg,
1925                                              section,
1926                                              "BINARY",
1927                                              &binary))
1928   {
1929     /* not a service section */
1930     return;
1931   }
1932   if ((GNUNET_YES ==
1933        GNUNET_CONFIGURATION_have_value (cfg,
1934                                         section,
1935                                         "USER_SERVICE")) &&
1936       (GNUNET_YES ==
1937        GNUNET_CONFIGURATION_get_value_yesno (cfg,
1938                                              section,
1939                                              "USER_SERVICE")))
1940   {
1941     if (GNUNET_NO == start_user)
1942     {
1943       GNUNET_free (binary);
1944       return; /* user service, and we don't deal with those */
1945     }
1946   }
1947   else
1948   {
1949     if (GNUNET_NO == start_system)
1950     {
1951       GNUNET_free (binary);
1952       return; /* system service, and we don't deal with those */
1953     }
1954   }
1955   sl = find_service (section);
1956   if (NULL != sl)
1957   {
1958     /* got the same section twice!? */
1959     GNUNET_break (0);
1960     GNUNET_free (binary);
1961     return;
1962   }
1963   config = NULL;
1964   if (( (GNUNET_OK !=
1965          GNUNET_CONFIGURATION_get_value_filename (cfg,
1966                                                   section,
1967                                                   "CONFIG",
1968                                                   &config)) &&
1969         (GNUNET_OK !=
1970          GNUNET_CONFIGURATION_get_value_filename (cfg,
1971                                                   "PATHS",
1972                                                   "DEFAULTCONFIG",
1973                                                   &config)) ) ||
1974       (0 != STAT (config, &sbuf)))
1975   {
1976     if (NULL != config)
1977     {
1978       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1979                                  section, "CONFIG",
1980                                  STRERROR (errno));
1981       GNUNET_free (config);
1982       config = NULL;
1983     }
1984   }
1985   sl = GNUNET_new (struct ServiceList);
1986   sl->name = GNUNET_strdup (section);
1987   sl->binary = binary;
1988   sl->config = config;
1989   sl->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
1990   sl->restart_at = GNUNET_TIME_UNIT_FOREVER_ABS;
1991 #if WINDOWS
1992   sl->pipe_control = GNUNET_YES;
1993 #else
1994   if (GNUNET_CONFIGURATION_have_value (cfg,
1995                                        section,
1996                                        "PIPECONTROL"))
1997     sl->pipe_control = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1998                                                              section,
1999                                                              "PIPECONTROL");
2000 #endif
2001   GNUNET_CONTAINER_DLL_insert (running_head,
2002                                running_tail,
2003                                sl);
2004   if (GNUNET_YES ==
2005       GNUNET_CONFIGURATION_get_value_yesno (cfg,
2006                                             section,
2007                                             "FORCESTART"))
2008   {
2009     sl->force_start = GNUNET_YES;
2010     if (GNUNET_YES ==
2011         GNUNET_CONFIGURATION_get_value_yesno (cfg,
2012                                               section,
2013                                               "NOARMBIND"))
2014       return;
2015   }
2016   else
2017   {
2018     if (GNUNET_YES !=
2019         GNUNET_CONFIGURATION_get_value_yesno (cfg,
2020                                               section,
2021                                               "AUTOSTART"))
2022       return;
2023   }
2024   if (0 >= (ret = get_server_addresses (section,
2025                                         cfg,
2026                                         &addrs,
2027                                         &addr_lens)))
2028     return;
2029   /* this will free (or capture) addrs[i] */
2030   for (i = 0; i < ret; i++)
2031     create_listen_socket (addrs[i],
2032                           addr_lens[i],
2033                           sl);
2034   GNUNET_free (addrs);
2035   GNUNET_free (addr_lens);
2036 }
2037
2038
2039 /**
2040  * A client connected, mark as a monitoring client.
2041  *
2042  * @param cls closure
2043  * @param client identification of the client
2044  * @param mq queue to talk to @a client
2045  * @return @a client
2046  */
2047 static void *
2048 client_connect_cb (void *cls,
2049                    struct GNUNET_SERVICE_Client *client,
2050                    struct GNUNET_MQ_Handle *mq)
2051 {
2052   /* All clients are considered to be of the "monitor" kind
2053    * (that is, they don't affect ARM shutdown).
2054    */
2055   GNUNET_SERVICE_client_mark_monitor (client);
2056   return client;
2057 }
2058
2059
2060 /**
2061  * A client disconnected, clean up associated state.
2062  *
2063  * @param cls closure
2064  * @param client identification of the client
2065  * @param app_ctx must match @a client
2066  */
2067 static void
2068 client_disconnect_cb (void *cls,
2069                       struct GNUNET_SERVICE_Client *client,
2070                       void *app_ctx)
2071 {
2072   struct ServiceList *sl;
2073
2074   GNUNET_assert (client == app_ctx);
2075
2076   for (sl = running_head; NULL != sl; sl = sl->next)
2077     if (sl->killing_client == client)
2078       sl->killing_client = NULL;
2079 }
2080
2081
2082 /**
2083  * Handle MONITOR-message.
2084  *
2085  * @param cls identification of the client
2086  * @param message the actual message
2087  * @return #GNUNET_OK to keep the connection open,
2088  *         #GNUNET_SYSERR to close it (signal serious error)
2089  */
2090 static void
2091 handle_monitor (void *cls,
2092                 const struct GNUNET_MessageHeader *message)
2093 {
2094   struct GNUNET_SERVICE_Client *client = cls;
2095
2096   /* FIXME: might want to start by letting monitor know about
2097      services that are already running */
2098   /* Removal is handled by the server implementation, internally. */
2099   GNUNET_notification_context_add (notifier,
2100                                    GNUNET_SERVICE_client_get_mq (client));
2101   broadcast_status ("arm",
2102                     GNUNET_ARM_SERVICE_MONITORING_STARTED,
2103                     client);
2104   GNUNET_SERVICE_client_continue (client);
2105 }
2106
2107
2108 /**
2109  * Process arm requests.
2110  *
2111  * @param cls closure
2112  * @param serv the initialized service
2113  * @param c configuration to use
2114  */
2115 static void
2116 run (void *cls,
2117      const struct GNUNET_CONFIGURATION_Handle *c,
2118      struct GNUNET_SERVICE_Handle *serv)
2119 {
2120   struct ServiceList *sl;
2121
2122   cfg = c;
2123   service = serv;
2124   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
2125                                  NULL);
2126   child_death_task =
2127     GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
2128                                     GNUNET_DISK_pipe_handle (sigpipe,
2129                                                              GNUNET_DISK_PIPE_END_READ),
2130                                     &maint_child_death,
2131                                     NULL);
2132 #if HAVE_WAIT4
2133   if (GNUNET_OK ==
2134       GNUNET_CONFIGURATION_get_value_filename (cfg,
2135                                                "ARM",
2136                                                "RESOURCE_DIAGNOSTICS",
2137                                                &wait_filename))
2138   {
2139     wait_file = fopen (wait_filename,
2140                        "w");
2141     if (NULL == wait_file)
2142     {
2143       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
2144                                 "fopen",
2145                                 wait_filename);
2146     }
2147   }
2148 #endif
2149   if (GNUNET_OK !=
2150       GNUNET_CONFIGURATION_get_value_string (cfg,
2151                                              "ARM",
2152                                              "GLOBAL_PREFIX",
2153                                              &prefix_command))
2154     prefix_command = GNUNET_strdup ("");
2155   else
2156     prefix_command = GNUNET_CONFIGURATION_expand_dollar (cfg,
2157                                                          prefix_command);
2158   if (GNUNET_OK !=
2159       GNUNET_CONFIGURATION_get_value_string (cfg,
2160                                              "ARM",
2161                                              "GLOBAL_POSTFIX",
2162                                              &final_option))
2163     final_option = GNUNET_strdup ("");
2164   else
2165     final_option = GNUNET_CONFIGURATION_expand_dollar (cfg,
2166                                                        final_option);
2167   if (GNUNET_YES ==
2168       GNUNET_CONFIGURATION_get_value_yesno (cfg,
2169                                             "ARM",
2170                                             "USER_ONLY"))
2171   {
2172     GNUNET_break (GNUNET_YES == start_user);
2173     start_system = GNUNET_NO;
2174   }
2175   if (GNUNET_YES ==
2176       GNUNET_CONFIGURATION_get_value_yesno (cfg,
2177                                             "ARM",
2178                                             "SYSTEM_ONLY"))
2179   {
2180     GNUNET_break (GNUNET_YES == start_system);
2181     start_user = GNUNET_NO;
2182   }
2183   GNUNET_CONFIGURATION_iterate_sections (cfg,
2184                                          &setup_service,
2185                                          NULL);
2186
2187   /* start default services... */
2188   for (sl = running_head; NULL != sl; sl = sl->next)
2189     if (GNUNET_YES == sl->force_start)
2190       start_process (sl,
2191                      NULL,
2192                      0);
2193   notifier = GNUNET_notification_context_create (MAX_NOTIFY_QUEUE);
2194 }
2195
2196
2197 /**
2198  * The main function for the arm service.
2199  *
2200  * @param argc number of arguments from the command line
2201  * @param argv command line arguments
2202  * @return 0 ok, 1 on error
2203  */
2204 int
2205 main (int argc,
2206       char *const *argv)
2207 {
2208   int ret;
2209   struct GNUNET_SIGNAL_Context *shc_chld;
2210   struct GNUNET_MQ_MessageHandler handlers[] = {
2211     GNUNET_MQ_hd_var_size (start,
2212                            GNUNET_MESSAGE_TYPE_ARM_START,
2213                            struct GNUNET_ARM_Message,
2214                            NULL),
2215     GNUNET_MQ_hd_var_size (stop,
2216                            GNUNET_MESSAGE_TYPE_ARM_STOP,
2217                            struct GNUNET_ARM_Message,
2218                            NULL),
2219     GNUNET_MQ_hd_fixed_size (monitor,
2220                              GNUNET_MESSAGE_TYPE_ARM_MONITOR,
2221                              struct GNUNET_MessageHeader,
2222                              NULL),
2223     GNUNET_MQ_hd_fixed_size (list,
2224                              GNUNET_MESSAGE_TYPE_ARM_LIST,
2225                              struct GNUNET_ARM_Message,
2226                              NULL),
2227     GNUNET_MQ_hd_fixed_size (test,
2228                              GNUNET_MESSAGE_TYPE_ARM_TEST,
2229                              struct GNUNET_MessageHeader,
2230                              NULL),
2231     GNUNET_MQ_handler_end ()
2232   };
2233
2234   sigpipe = GNUNET_DISK_pipe (GNUNET_NO,
2235                               GNUNET_NO,
2236                               GNUNET_NO,
2237                               GNUNET_NO);
2238   GNUNET_assert (NULL != sigpipe);
2239   shc_chld =
2240     GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD,
2241                                    &sighandler_child_death);
2242   ret = GNUNET_SERVICE_run_ (argc,
2243                              argv,
2244                              "arm",
2245                              GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN,
2246                              &run,
2247                              &client_connect_cb,
2248                              &client_disconnect_cb,
2249                              NULL,
2250                              handlers);
2251 #if HAVE_WAIT4
2252   if (NULL != wait_file)
2253   {
2254     fclose (wait_file);
2255     wait_file = NULL;
2256   }
2257   if (NULL != wait_filename)
2258   {
2259     GNUNET_free (wait_filename);
2260     wait_filename = NULL;
2261   }
2262 #endif
2263   GNUNET_SIGNAL_handler_uninstall (shc_chld);
2264   shc_chld = NULL;
2265   GNUNET_DISK_pipe_close (sigpipe);
2266   sigpipe = NULL;
2267   return ret;
2268 }
2269
2270
2271 #if defined(LINUX) && defined(__GLIBC__)
2272 #include <malloc.h>
2273
2274 /**
2275  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
2276  */
2277 void __attribute__ ((constructor)) GNUNET_ARM_memory_init ()
2278 {
2279   mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2280   mallopt (M_TOP_PAD, 1 * 1024);
2281   malloc_trim (0);
2282 }
2283 #endif
2284
2285
2286 /* end of gnunet-service-arm.c */