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