- doc
[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_IN_SIN_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 (optpos);
816     }
817     else
818     {
819       /* only have "fin_options", use that */
820       options = fin_options;
821     }
822   }
823   options = GNUNET_CONFIGURATION_expand_dollar (cfg,
824                                                 options);
825   use_debug = GNUNET_CONFIGURATION_get_value_yesno (cfg,
826                                                     sl->name,
827                                                     "DEBUG");
828   {
829     const char *service_type = NULL;
830     const char *choices[] = { "GNUNET", "SIMPLE", NULL };
831
832     is_simple_service = GNUNET_NO;
833     if ( (GNUNET_OK ==
834           GNUNET_CONFIGURATION_get_value_choice (cfg,
835                                                  sl->name,
836                                                  "TYPE",
837                                                  choices,
838                                                  &service_type)) &&
839          (0 == strcasecmp (service_type, "SIMPLE")) )
840       is_simple_service = GNUNET_YES;
841   }
842
843   GNUNET_assert (NULL == sl->proc);
844   if (GNUNET_YES == is_simple_service)
845   {
846     /* A simple service will receive no GNUnet specific
847        command line options. */
848     binary = GNUNET_strdup (sl->binary);
849     binary = GNUNET_CONFIGURATION_expand_dollar (cfg, binary);
850     GNUNET_asprintf (&quotedbinary,
851                      "\"%s\"",
852                      sl->binary);
853     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
854                 "Starting simple service `%s' using binary `%s'\n",
855                 sl->name, sl->binary);
856     /* FIXME: dollar expansion should only be done outside
857      * of ''-quoted strings, escaping should be considered. */
858     if (NULL != options)
859       options = GNUNET_CONFIGURATION_expand_dollar (cfg, options);
860     sl->proc =
861       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, sl->binary, sl->config);
875     binary = GNUNET_OS_get_libexec_binary_path (sl->binary);
876     GNUNET_asprintf (&quotedbinary,
877                      "\"%s\"",
878                      binary);
879
880     if (GNUNET_YES == use_debug)
881     {
882       if (NULL == sl->config)
883         sl->proc =
884           GNUNET_OS_start_process_s (sl->pipe_control,
885                                      GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
886                                      lsocks,
887                                      loprefix,
888                                      quotedbinary,
889                                      "-L", "DEBUG",
890                                      options,
891                                      NULL);
892       else
893         sl->proc =
894             GNUNET_OS_start_process_s (sl->pipe_control,
895                                        GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
896                                        lsocks,
897                                        loprefix,
898                                        quotedbinary,
899                                        "-c", sl->config,
900                                        "-L", "DEBUG",
901                                        options,
902                                        NULL);
903     }
904     else
905     {
906       if (NULL == sl->config)
907         sl->proc =
908             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 =
917             GNUNET_OS_start_process_s (sl->pipe_control,
918                                        GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
919                                        lsocks,
920                                        loprefix,
921                                        quotedbinary,
922                                        "-c", sl->config,
923                                        options,
924                                        NULL);
925     }
926   }
927   GNUNET_free (binary);
928   GNUNET_free (quotedbinary);
929   if (NULL == sl->proc)
930   {
931     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
932                 _("Failed to start service `%s'\n"),
933                 sl->name);
934     if (client)
935       signal_result (client,
936                      sl->name,
937                      request_id,
938                      GNUNET_ARM_RESULT_START_FAILED);
939   }
940   else
941   {
942     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
943                 _("Starting service `%s'\n"),
944                 sl->name);
945     broadcast_status (sl->name,
946                       GNUNET_ARM_SERVICE_STARTING,
947                       NULL);
948     if (client)
949       signal_result (client,
950                      sl->name,
951                      request_id,
952                      GNUNET_ARM_RESULT_STARTING);
953   }
954   /* clean up */
955   GNUNET_free (loprefix);
956   GNUNET_free (options);
957   GNUNET_array_grow (lsocks,
958                      ls,
959                      0);
960 }
961
962
963 /**
964  * Find the process with the given service
965  * name in the given list and return it.
966  *
967  * @param name which service entry to look up
968  * @return NULL if it was not found
969  */
970 static struct ServiceList *
971 find_service (const char *name)
972 {
973   struct ServiceList *sl;
974
975   sl = running_head;
976   while (sl != NULL)
977     {
978       if (0 == strcasecmp (sl->name, name))
979         return sl;
980       sl = sl->next;
981     }
982   return NULL;
983 }
984
985
986 /**
987  * First connection has come to the listening socket associated with the service,
988  * create the service in order to relay the incoming connection to it
989  *
990  * @param cls callback data, `struct ServiceListeningInfo` describing a listen socket
991  */
992 static void
993 accept_connection (void *cls)
994 {
995   struct ServiceListeningInfo *sli = cls;
996   struct ServiceList *sl = sli->sl;
997
998   sli->accept_task = NULL;
999   GNUNET_assert (GNUNET_NO == in_shutdown);
1000   start_process (sl, NULL, 0);
1001 }
1002
1003
1004 /**
1005  * Creating a listening socket for each of the service's addresses and
1006  * wait for the first incoming connection to it
1007  *
1008  * @param sa address associated with the service
1009  * @param addr_len length of @a sa
1010  * @param sl service entry for the service in question
1011  */
1012 static void
1013 create_listen_socket (struct sockaddr *sa,
1014                       socklen_t addr_len,
1015                       struct ServiceList *sl)
1016 {
1017   static int on = 1;
1018   struct GNUNET_NETWORK_Handle *sock;
1019   struct ServiceListeningInfo *sli;
1020 #ifndef WINDOWS
1021   int match_uid;
1022   int match_gid;
1023 #endif
1024
1025   switch (sa->sa_family)
1026   {
1027   case AF_INET:
1028     sock = GNUNET_NETWORK_socket_create (PF_INET,
1029                                          SOCK_STREAM,
1030                                          0);
1031     break;
1032   case AF_INET6:
1033     sock = GNUNET_NETWORK_socket_create (PF_INET6,
1034                                          SOCK_STREAM,
1035                                          0);
1036     break;
1037   case AF_UNIX:
1038     if (0 == strcmp (GNUNET_a2s (sa,
1039                                  addr_len),
1040                      "@"))      /* Do not bind to blank UNIX path! */
1041       return;
1042     sock = GNUNET_NETWORK_socket_create (PF_UNIX,
1043                                          SOCK_STREAM,
1044                                          0);
1045     break;
1046   default:
1047     GNUNET_break (0);
1048     sock = NULL;
1049     errno = EAFNOSUPPORT;
1050     break;
1051   }
1052   if (NULL == sock)
1053   {
1054     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1055                 _("Unable to create socket for service `%s': %s\n"),
1056                 sl->name,
1057                 STRERROR (errno));
1058     GNUNET_free (sa);
1059     return;
1060   }
1061   if (GNUNET_OK !=
1062       GNUNET_NETWORK_socket_setsockopt (sock,
1063                                         SOL_SOCKET,
1064                                         SO_REUSEADDR,
1065                                         &on,
1066                                         sizeof (on)))
1067     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1068                          "setsockopt");
1069 #ifdef IPV6_V6ONLY
1070   if ( (sa->sa_family == AF_INET6) &&
1071        (GNUNET_OK !=
1072         GNUNET_NETWORK_socket_setsockopt (sock,
1073                                           IPPROTO_IPV6,
1074                                           IPV6_V6ONLY,
1075                                           &on,
1076                                           sizeof (on))) )
1077     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1078                          "setsockopt");
1079 #endif
1080 #ifndef WINDOWS
1081   if (AF_UNIX == sa->sa_family)
1082     GNUNET_NETWORK_unix_precheck ((struct sockaddr_un *) sa);
1083 #endif
1084   if (GNUNET_OK !=
1085       GNUNET_NETWORK_socket_bind (sock,
1086                                   (const struct sockaddr *) sa,
1087                                   addr_len))
1088   {
1089     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1090                 _("Unable to bind listening socket for service `%s' to address `%s': %s\n"),
1091                 sl->name,
1092                 GNUNET_a2s (sa,
1093                             addr_len),
1094                 STRERROR (errno));
1095     GNUNET_break (GNUNET_OK ==
1096                   GNUNET_NETWORK_socket_close (sock));
1097     GNUNET_free (sa);
1098     return;
1099   }
1100 #ifndef WINDOWS
1101   if ((AF_UNIX == sa->sa_family)
1102 #ifdef LINUX
1103       /* Permission settings are not required when abstract sockets are used */
1104       && ('\0' != ((const struct sockaddr_un *)sa)->sun_path[0])
1105 #endif
1106       )
1107   {
1108     match_uid =
1109       GNUNET_CONFIGURATION_get_value_yesno (cfg,
1110                                             sl->name,
1111                                             "UNIX_MATCH_UID");
1112     match_gid =
1113       GNUNET_CONFIGURATION_get_value_yesno (cfg,
1114                                             sl->name,
1115                                             "UNIX_MATCH_GID");
1116     GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sa)->sun_path,
1117                                  match_uid,
1118                                  match_gid);
1119
1120   }
1121 #endif
1122   if (GNUNET_OK !=
1123       GNUNET_NETWORK_socket_listen (sock, 5))
1124   {
1125     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1126                          "listen");
1127     GNUNET_break (GNUNET_OK ==
1128                   GNUNET_NETWORK_socket_close (sock));
1129     GNUNET_free (sa);
1130     return;
1131   }
1132   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1133               _("ARM now monitors connections to service `%s' at `%s'\n"),
1134               sl->name,
1135               GNUNET_a2s (sa,
1136                           addr_len));
1137   sli = GNUNET_new (struct ServiceListeningInfo);
1138   sli->service_addr = sa;
1139   sli->service_addr_len = addr_len;
1140   sli->listen_socket = sock;
1141   sli->sl = sl;
1142   sli->accept_task
1143     = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1144                                      sock,
1145                                      &accept_connection, sli);
1146   GNUNET_CONTAINER_DLL_insert (sl->listen_head,
1147                                sl->listen_tail,
1148                                sli);
1149 }
1150
1151
1152 /**
1153  * Remove and free an entry in the service list.  Listen sockets
1154  * must have already been cleaned up.  Only to be called during shutdown.
1155  *
1156  * @param sl entry to free
1157  */
1158 static void
1159 free_service (struct ServiceList *sl)
1160 {
1161   GNUNET_assert (GNUNET_YES == in_shutdown);
1162   GNUNET_CONTAINER_DLL_remove (running_head,
1163                                running_tail,
1164                                sl);
1165   GNUNET_assert (NULL == sl->listen_head);
1166   GNUNET_free_non_null (sl->config);
1167   GNUNET_free_non_null (sl->binary);
1168   GNUNET_free (sl->name);
1169   GNUNET_free (sl);
1170 }
1171
1172
1173 /**
1174  * Check START-message.
1175  *
1176  * @param cls identification of the client
1177  * @param amsg the actual message
1178  * @return #GNUNET_OK to keep the connection open,
1179  *         #GNUNET_SYSERR to close it (signal serious error)
1180  */
1181 static int
1182 check_start (void *cls,
1183              const struct GNUNET_ARM_Message *amsg)
1184 {
1185   uint16_t size;
1186   const char *servicename;
1187
1188   size = ntohs (amsg->header.size) - sizeof (struct GNUNET_ARM_Message);
1189   servicename = (const char *) &amsg[1];
1190   if ( (0 == size) ||
1191        (servicename[size - 1] != '\0') )
1192   {
1193     GNUNET_break (0);
1194     return GNUNET_SYSERR;
1195   }
1196   return GNUNET_OK;
1197 }
1198
1199
1200 /**
1201  * Handle START-message.
1202  *
1203  * @param cls identification of the client
1204  * @param amsg the actual message
1205  */
1206 static void
1207 handle_start (void *cls,
1208               const struct GNUNET_ARM_Message *amsg)
1209 {
1210   struct GNUNET_SERVICE_Client *client = cls;
1211   const char *servicename;
1212   struct ServiceList *sl;
1213   uint64_t request_id;
1214
1215   request_id = GNUNET_ntohll (amsg->request_id);
1216   servicename = (const char *) &amsg[1];
1217   GNUNET_SERVICE_client_continue (client);
1218   if (GNUNET_YES == in_shutdown)
1219   {
1220     signal_result (client,
1221                    servicename,
1222                    request_id,
1223                    GNUNET_ARM_RESULT_IN_SHUTDOWN);
1224     return;
1225   }
1226   sl = find_service (servicename);
1227   if (NULL == sl)
1228   {
1229     signal_result (client,
1230                    servicename,
1231                    request_id,
1232                    GNUNET_ARM_RESULT_IS_NOT_KNOWN);
1233     return;
1234   }
1235   sl->force_start = GNUNET_YES;
1236   if (NULL != sl->proc)
1237   {
1238     signal_result (client,
1239                    servicename,
1240                    request_id,
1241                    GNUNET_ARM_RESULT_IS_STARTED_ALREADY);
1242     return;
1243   }
1244   start_process (sl,
1245                  client,
1246                  request_id);
1247 }
1248
1249
1250 /**
1251  * Start a shutdown sequence.
1252  *
1253  * @param cls closure (refers to service)
1254  */
1255 static void
1256 trigger_shutdown (void *cls)
1257 {
1258   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1259               "Triggering shutdown\n");
1260   GNUNET_SCHEDULER_shutdown ();
1261 }
1262
1263
1264 /**
1265  * Check STOP-message.
1266  *
1267  * @param cls identification of the client
1268  * @param amsg the actual message
1269  * @return #GNUNET_OK to keep the connection open,
1270  *         #GNUNET_SYSERR to close it (signal serious error)
1271  */
1272 static int
1273 check_stop (void *cls,
1274             const struct GNUNET_ARM_Message *amsg)
1275 {
1276   uint16_t size;
1277   const char *servicename;
1278
1279   size = ntohs (amsg->header.size) - sizeof (struct GNUNET_ARM_Message);
1280   servicename = (const char *) &amsg[1];
1281   if ( (0 == size) ||
1282        (servicename[size - 1] != '\0') )
1283   {
1284     GNUNET_break (0);
1285     return GNUNET_SYSERR;
1286   }
1287   return GNUNET_OK;
1288 }
1289
1290
1291 /**
1292  * Handle STOP-message.
1293  *
1294  * @param cls identification of the client
1295  * @param amsg the actual message
1296  */
1297 static void
1298 handle_stop (void *cls,
1299              const struct GNUNET_ARM_Message *amsg)
1300 {
1301   struct GNUNET_SERVICE_Client *client = cls;
1302   struct ServiceList *sl;
1303   const char *servicename;
1304   uint64_t request_id;
1305
1306   request_id = GNUNET_ntohll (amsg->request_id);
1307   servicename = (const char *) &amsg[1];
1308   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1309               _("Preparing to stop `%s'\n"),
1310               servicename);
1311   GNUNET_SERVICE_client_continue (client);
1312   if (0 == strcasecmp (servicename,
1313                        "arm"))
1314   {
1315     broadcast_status (servicename,
1316                       GNUNET_ARM_SERVICE_STOPPING,
1317                       NULL);
1318     signal_result (client,
1319                    servicename,
1320                    request_id,
1321                    GNUNET_ARM_RESULT_STOPPING);
1322     GNUNET_SERVICE_client_persist (client);
1323     GNUNET_SCHEDULER_add_now (&trigger_shutdown,
1324                               NULL);
1325     return;
1326   }
1327   sl = find_service (servicename);
1328   if (NULL == sl)
1329   {
1330     signal_result (client,
1331                    servicename,
1332                    request_id,
1333                    GNUNET_ARM_RESULT_IS_NOT_KNOWN);
1334     return;
1335   }
1336   sl->force_start = GNUNET_NO;
1337   if (GNUNET_YES == in_shutdown)
1338   {
1339     /* shutdown in progress */
1340     signal_result (client,
1341                    servicename,
1342                    request_id,
1343                    GNUNET_ARM_RESULT_IN_SHUTDOWN);
1344     return;
1345   }
1346   if (NULL != sl->killing_client)
1347   {
1348     /* killing already in progress */
1349     signal_result (client,
1350                    servicename,
1351                    request_id,
1352                    GNUNET_ARM_RESULT_IS_STOPPING_ALREADY);
1353     return;
1354   }
1355   if (NULL == sl->proc)
1356   {
1357     /* process is down */
1358     signal_result (client,
1359                    servicename,
1360                    request_id,
1361                    GNUNET_ARM_RESULT_IS_STOPPED_ALREADY);
1362     return;
1363   }
1364   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1365               "Sending kill signal to service `%s', waiting for process to die.\n",
1366               servicename);
1367   broadcast_status (servicename,
1368                     GNUNET_ARM_SERVICE_STOPPING,
1369                     NULL);
1370   /* no signal_start - only when it's STOPPED */
1371   sl->killed_at = GNUNET_TIME_absolute_get ();
1372   if (0 != GNUNET_OS_process_kill (sl->proc,
1373                                    GNUNET_TERM_SIG))
1374     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1375                          "kill");
1376   sl->killing_client = client;
1377   sl->killing_client_request_id = request_id;
1378 }
1379
1380
1381 /**
1382  * Handle LIST-message.
1383  *
1384  * @param cls identification of the client
1385  * @param message the actual message
1386  */
1387 static void
1388 handle_list (void *cls,
1389              const struct GNUNET_ARM_Message *request)
1390 {
1391   struct GNUNET_SERVICE_Client *client = cls;
1392   struct GNUNET_MQ_Envelope *env;
1393   struct GNUNET_ARM_ListResultMessage *msg;
1394   size_t string_list_size;
1395   struct ServiceList *sl;
1396   uint16_t count;
1397   char *pos;
1398
1399   GNUNET_break (0 == ntohl (request->reserved));
1400   count = 0;
1401   string_list_size = 0;
1402
1403   /* first count the running processes get their name's size */
1404   for (sl = running_head; NULL != sl; sl = sl->next)
1405   {
1406     if (NULL != sl->proc)
1407     {
1408       string_list_size += strlen (sl->name);
1409       string_list_size += strlen (sl->binary);
1410       string_list_size += 4;
1411       count++;
1412     }
1413   }
1414
1415   env = GNUNET_MQ_msg_extra (msg,
1416                              string_list_size,
1417                              GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT);
1418   msg->arm_msg.request_id = request->request_id;
1419   msg->count = htons (count);
1420
1421   pos = (char *) &msg[1];
1422   for (sl = running_head; NULL != sl; sl = sl->next)
1423   {
1424     if (NULL != sl->proc)
1425     {
1426       size_t s = strlen (sl->name) + strlen (sl->binary) + 4;
1427       GNUNET_snprintf (pos,
1428                        s,
1429                        "%s (%s)",
1430                        sl->name,
1431                        sl->binary);
1432       pos += s;
1433     }
1434   }
1435   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
1436                   env);
1437   GNUNET_SERVICE_client_continue (client);
1438 }
1439
1440
1441 /**
1442  * Handle TEST-message by sending back TEST.
1443  *
1444  * @param cls identification of the client
1445  * @param message the actual message
1446  */
1447 static void
1448 handle_test (void *cls,
1449              const struct GNUNET_MessageHeader *message)
1450 {
1451   struct GNUNET_SERVICE_Client *client = cls;
1452   struct GNUNET_MQ_Envelope *env;
1453   struct GNUNET_MessageHeader *msg;
1454
1455   env = GNUNET_MQ_msg (msg,
1456                        GNUNET_MESSAGE_TYPE_ARM_TEST);
1457   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
1458                   env);
1459   GNUNET_SERVICE_client_continue (client);
1460 }
1461
1462
1463 /**
1464  * We are done with everything.  Stop remaining
1465  * tasks, signal handler and the server.
1466  */
1467 static void
1468 do_shutdown ()
1469 {
1470   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1471               "Last shutdown phase\n");
1472   if (NULL != notifier)
1473   {
1474     GNUNET_notification_context_destroy (notifier);
1475     notifier = NULL;
1476   }
1477   if (NULL != service)
1478   {
1479     GNUNET_SERVICE_shutdown (service);
1480     service = NULL;
1481   }
1482   if (NULL != child_death_task)
1483   {
1484     GNUNET_SCHEDULER_cancel (child_death_task);
1485     child_death_task = NULL;
1486   }
1487 }
1488
1489
1490 /**
1491  * Count how many services are still active.
1492  *
1493  * @param running_head list of services
1494  * @return number of active services found
1495  */
1496 static unsigned int
1497 list_count (struct ServiceList *running_head)
1498 {
1499   struct ServiceList *i;
1500   unsigned int res;
1501
1502   for (res = 0, i = running_head; i; i = i->next, res++)
1503     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1504                 "%s\n",
1505                 i->name);
1506   return res;
1507 }
1508
1509
1510 /**
1511  * Task run for shutdown.
1512  *
1513  * @param cls closure, NULL if we need to self-restart
1514  */
1515 static void
1516 shutdown_task (void *cls)
1517 {
1518   struct ServiceList *pos;
1519   struct ServiceList *nxt;
1520   struct ServiceListeningInfo *sli;
1521
1522   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1523               "First shutdown phase\n");
1524   if (NULL != child_restart_task)
1525   {
1526     GNUNET_SCHEDULER_cancel (child_restart_task);
1527     child_restart_task = NULL;
1528   }
1529   in_shutdown = GNUNET_YES;
1530   /* first, stop listening */
1531   for (pos = running_head; NULL != pos; pos = pos->next)
1532   {
1533     while (NULL != (sli = pos->listen_head))
1534     {
1535       GNUNET_CONTAINER_DLL_remove (pos->listen_head,
1536                                    pos->listen_tail,
1537                                    sli);
1538       if (NULL != sli->accept_task)
1539       {
1540         GNUNET_SCHEDULER_cancel (sli->accept_task);
1541         sli->accept_task = NULL;
1542       }
1543       GNUNET_break (GNUNET_OK ==
1544                     GNUNET_NETWORK_socket_close (sli->listen_socket));
1545       GNUNET_free (sli->service_addr);
1546       GNUNET_free (sli);
1547     }
1548   }
1549   /* then, shutdown all existing service processes */
1550   nxt = running_head;
1551   while (NULL != (pos = nxt))
1552   {
1553     nxt = pos->next;
1554     if (NULL != pos->proc)
1555     {
1556       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1557                   "Stopping service `%s'\n",
1558                   pos->name);
1559       pos->killed_at = GNUNET_TIME_absolute_get ();
1560       if (0 != GNUNET_OS_process_kill (pos->proc,
1561                                        GNUNET_TERM_SIG))
1562         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1563                              "kill");
1564     }
1565     else
1566     {
1567       free_service (pos);
1568     }
1569   }
1570   /* finally, should all service processes be already gone, terminate for real */
1571   if (NULL == running_head)
1572     do_shutdown ();
1573   else
1574     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1575                 "Delaying shutdown, have %u childs still running\n",
1576                 list_count (running_head));
1577 }
1578
1579
1580 /**
1581  * Task run whenever it is time to restart a child that died.
1582  *
1583  * @param cls closure, always NULL
1584  */
1585 static void
1586 delayed_restart_task (void *cls)
1587
1588 {
1589   struct ServiceList *sl;
1590   struct GNUNET_TIME_Relative lowestRestartDelay;
1591   struct ServiceListeningInfo *sli;
1592
1593   child_restart_task = NULL;
1594   GNUNET_assert (GNUNET_NO == in_shutdown);
1595   lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL;
1596
1597   /* check for services that need to be restarted due to
1598    * configuration changes or because the last restart failed */
1599   for (sl = running_head; NULL != sl; sl = sl->next)
1600   {
1601     if (NULL != sl->proc)
1602       continue;
1603     /* service is currently not running */
1604     if (0 == GNUNET_TIME_absolute_get_remaining (sl->restart_at).rel_value_us)
1605     {
1606       /* restart is now allowed */
1607       if (sl->force_start)
1608       {
1609         /* process should run by default, start immediately */
1610         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1611                     _("Restarting service `%s'.\n"),
1612                     sl->name);
1613         start_process (sl,
1614                        NULL,
1615                        0);
1616       }
1617       else
1618       {
1619         /* process is run on-demand, ensure it is re-started if there is demand */
1620         for (sli = sl->listen_head; NULL != sli; sli = sli->next)
1621           if (NULL == sli->accept_task)
1622           {
1623             /* accept was actually paused, so start it again */
1624             sli->accept_task
1625               = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1626                                                sli->listen_socket,
1627                                                &accept_connection,
1628                                                sli);
1629           }
1630       }
1631     }
1632     else
1633     {
1634       /* update calculation for earliest time to reactivate a service */
1635       lowestRestartDelay =
1636         GNUNET_TIME_relative_min (lowestRestartDelay,
1637                                   GNUNET_TIME_absolute_get_remaining
1638                                   (sl->restart_at));
1639     }
1640   }
1641   if (lowestRestartDelay.rel_value_us != GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1642   {
1643     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1644                 "Will restart process in %s\n",
1645                 GNUNET_STRINGS_relative_time_to_string (lowestRestartDelay,
1646                                                         GNUNET_YES));
1647     child_restart_task =
1648       GNUNET_SCHEDULER_add_delayed_with_priority (lowestRestartDelay,
1649                                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
1650                                                   &delayed_restart_task,
1651                                                   NULL);
1652   }
1653 }
1654
1655
1656 /**
1657  * Task triggered whenever we receive a SIGCHLD (child
1658  * process died).
1659  *
1660  * @param cls closure, NULL if we need to self-restart
1661  */
1662 static void
1663 maint_child_death (void *cls)
1664 {
1665   struct ServiceList *pos;
1666   struct ServiceList *next;
1667   struct ServiceListeningInfo *sli;
1668   const char *statstr;
1669   int statcode;
1670   int ret;
1671   char c[16];
1672   enum GNUNET_OS_ProcessStatusType statusType;
1673   unsigned long statusCode;
1674   const struct GNUNET_DISK_FileHandle *pr;
1675
1676   pr = GNUNET_DISK_pipe_handle (sigpipe,
1677                                 GNUNET_DISK_PIPE_END_READ);
1678   child_death_task = NULL;
1679   /* consume the signal */
1680   GNUNET_break (0 < GNUNET_DISK_file_read (pr,
1681                                            &c,
1682                                            sizeof (c)));
1683
1684   /* check for services that died (WAITPID) */
1685   next = running_head;
1686   while (NULL != (pos = next))
1687   {
1688     next = pos->next;
1689
1690     if (NULL == pos->proc)
1691     {
1692       if (GNUNET_YES == in_shutdown)
1693         free_service (pos);
1694       continue;
1695     }
1696 #if HAVE_WAIT4
1697     if (NULL != wait_file)
1698     {
1699       /* need to use 'wait4()' to obtain and log performance data */
1700       struct rusage ru;
1701       int status;
1702       pid_t pid;
1703
1704       pid = GNUNET_OS_process_get_pid (pos->proc);
1705       ret = wait4 (pid,
1706                    &status,
1707                    WNOHANG,
1708                    &ru);
1709       if (ret <= 0)
1710         continue; /* no process done */
1711       if (WIFEXITED (status))
1712       {
1713         statusType = GNUNET_OS_PROCESS_EXITED;
1714         statusCode = WEXITSTATUS (status);
1715       }
1716       else if (WIFSIGNALED (status))
1717       {
1718         statusType = GNUNET_OS_PROCESS_SIGNALED;
1719         statusCode = WTERMSIG (status);
1720       }
1721       else if (WIFSTOPPED (status))
1722       {
1723         statusType = GNUNET_OS_PROCESS_SIGNALED;
1724         statusCode = WSTOPSIG (status);
1725       }
1726 #ifdef WIFCONTINUED
1727       else if (WIFCONTINUED (status))
1728       {
1729         statusType = GNUNET_OS_PROCESS_RUNNING;
1730         statusCode = 0;
1731       }
1732 #endif
1733       else
1734       {
1735         statusType = GNUNET_OS_PROCESS_UNKNOWN;
1736         statusCode = 0;
1737       }
1738       if ( (GNUNET_OS_PROCESS_EXITED == statusType) ||
1739            (GNUNET_OS_PROCESS_SIGNALED == statusType) )
1740       {
1741         double utime = ru.ru_utime.tv_sec + (ru.ru_utime.tv_usec / 10e6);
1742         double stime = ru.ru_stime.tv_sec + (ru.ru_stime.tv_usec / 10e6);
1743         fprintf (wait_file,
1744                  "%s(%u) %.3f %.3f %llu %llu %llu %llu %llu\n",
1745                  pos->binary,
1746                  (unsigned int) pid,
1747                  utime,
1748                  stime,
1749                  (unsigned long long) ru.ru_maxrss,
1750                  (unsigned long long) ru.ru_inblock,
1751                  (unsigned long long) ru.ru_oublock,
1752                  (unsigned long long) ru.ru_nvcsw,
1753                  (unsigned long long) ru.ru_nivcsw);
1754       }
1755     }
1756     else /* continue with JUST this "if" as "else" (intentionally no brackets!) */
1757 #endif
1758     if ( (GNUNET_SYSERR ==
1759           (ret =
1760            GNUNET_OS_process_status (pos->proc,
1761                                      &statusType,
1762                                      &statusCode))) ||
1763          (ret == GNUNET_NO) ||
1764          (statusType == GNUNET_OS_PROCESS_STOPPED) ||
1765          (statusType == GNUNET_OS_PROCESS_UNKNOWN) ||
1766          (statusType == GNUNET_OS_PROCESS_RUNNING) )
1767       continue;
1768
1769     if (statusType == GNUNET_OS_PROCESS_EXITED)
1770     {
1771       statstr = _( /* process termination method */ "exit");
1772       statcode = statusCode;
1773     }
1774     else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
1775     {
1776       statstr = _( /* process termination method */ "signal");
1777       statcode = statusCode;
1778     }
1779     else
1780     {
1781       statstr = _( /* process termination method */ "unknown");
1782       statcode = 0;
1783     }
1784     if (0 != pos->killed_at.abs_value_us)
1785     {
1786       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1787                   _("Service `%s' took %s to terminate\n"),
1788                   pos->name,
1789                   GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->killed_at),
1790                                                           GNUNET_YES));
1791     }
1792     GNUNET_OS_process_destroy (pos->proc);
1793     pos->proc = NULL;
1794     broadcast_status (pos->name,
1795                       GNUNET_ARM_SERVICE_STOPPED,
1796                       NULL);
1797     if (NULL != pos->killing_client)
1798     {
1799       signal_result (pos->killing_client, pos->name,
1800                      pos->killing_client_request_id,
1801                      GNUNET_ARM_RESULT_STOPPED);
1802       pos->killing_client = NULL;
1803       pos->killing_client_request_id = 0;
1804     }
1805     if (GNUNET_YES != in_shutdown)
1806     {
1807       if ( (statusType == GNUNET_OS_PROCESS_EXITED) &&
1808            (statcode == 0) )
1809       {
1810         /* process terminated normally, allow restart at any time */
1811         pos->restart_at.abs_value_us = 0;
1812         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1813                     _("Service `%s' terminated normally, will restart at any time\n"),
1814                     pos->name);
1815         /* process can still be re-started on-demand, ensure it is re-started if there is demand */
1816         for (sli = pos->listen_head; NULL != sli; sli = sli->next)
1817         {
1818           GNUNET_break (NULL == sli->accept_task);
1819           sli->accept_task =
1820             GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1821                                            sli->listen_socket,
1822                                            &accept_connection,
1823                                            sli);
1824         }
1825       }
1826       else
1827       {
1828         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1829                     _("Service `%s' terminated with status %s/%d, will restart in %s\n"),
1830                     pos->name,
1831                     statstr,
1832                     statcode,
1833                     GNUNET_STRINGS_relative_time_to_string (pos->backoff,
1834                                                             GNUNET_YES));
1835         /* schedule restart */
1836         pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff);
1837         pos->backoff = GNUNET_TIME_STD_BACKOFF (pos->backoff);
1838         if (NULL != child_restart_task)
1839           GNUNET_SCHEDULER_cancel (child_restart_task);
1840         child_restart_task
1841           = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
1842                                                 &delayed_restart_task,
1843                                                 NULL);
1844       }
1845     }
1846     else
1847     {
1848       free_service (pos);
1849     }
1850   }
1851   child_death_task = GNUNET_SCHEDULER_add_read_file (
1852       GNUNET_TIME_UNIT_FOREVER_REL,
1853       pr,
1854       &maint_child_death, NULL);
1855   if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
1856     do_shutdown ();
1857   else if (GNUNET_YES == in_shutdown)
1858     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1859         "Delaying shutdown after child's death, still have %u children\n",
1860         list_count (running_head));
1861
1862 }
1863
1864
1865 /**
1866  * Signal handler called for SIGCHLD.  Triggers the
1867  * respective handler by writing to the trigger pipe.
1868  */
1869 static void
1870 sighandler_child_death ()
1871 {
1872   static char c;
1873   int old_errno = errno;        /* back-up errno */
1874
1875   GNUNET_break (1 ==
1876                 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (sigpipe,
1877                                                                  GNUNET_DISK_PIPE_END_WRITE),
1878                                         &c,
1879                                         sizeof (c)));
1880   errno = old_errno;            /* restore errno */
1881 }
1882
1883
1884 /**
1885  * Setup our service record for the given section in the configuration file
1886  * (assuming the section is for a service).
1887  *
1888  * @param cls unused
1889  * @param section a section in the configuration file
1890  * @return #GNUNET_OK (continue)
1891  */
1892 static void
1893 setup_service (void *cls,
1894                const char *section)
1895 {
1896   struct ServiceList *sl;
1897   char *binary;
1898   char *config;
1899   struct stat sbuf;
1900   struct sockaddr **addrs;
1901   socklen_t *addr_lens;
1902   int ret;
1903   unsigned int i;
1904
1905   if (0 == strcasecmp (section,
1906                        "arm"))
1907     return;
1908   if (GNUNET_OK !=
1909       GNUNET_CONFIGURATION_get_value_string (cfg,
1910                                              section,
1911                                              "BINARY",
1912                                              &binary))
1913   {
1914     /* not a service section */
1915     return;
1916   }
1917   if ((GNUNET_YES ==
1918        GNUNET_CONFIGURATION_have_value (cfg,
1919                                         section,
1920                                         "USER_SERVICE")) &&
1921       (GNUNET_YES ==
1922        GNUNET_CONFIGURATION_get_value_yesno (cfg,
1923                                              section,
1924                                              "USER_SERVICE")))
1925   {
1926     if (GNUNET_NO == start_user)
1927     {
1928       GNUNET_free (binary);
1929       return; /* user service, and we don't deal with those */
1930     }
1931   }
1932   else
1933   {
1934     if (GNUNET_NO == start_system)
1935     {
1936       GNUNET_free (binary);
1937       return; /* system service, and we don't deal with those */
1938     }
1939   }
1940   sl = find_service (section);
1941   if (NULL != sl)
1942   {
1943     /* got the same section twice!? */
1944     GNUNET_break (0);
1945     GNUNET_free (binary);
1946     return;
1947   }
1948   config = NULL;
1949   if (( (GNUNET_OK !=
1950          GNUNET_CONFIGURATION_get_value_filename (cfg,
1951                                                   section,
1952                                                   "CONFIG",
1953                                                   &config)) &&
1954         (GNUNET_OK !=
1955          GNUNET_CONFIGURATION_get_value_filename (cfg,
1956                                                   "PATHS",
1957                                                   "DEFAULTCONFIG",
1958                                                   &config)) ) ||
1959       (0 != STAT (config, &sbuf)))
1960   {
1961     if (NULL != config)
1962     {
1963       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1964                                  section, "CONFIG",
1965                                  STRERROR (errno));
1966       GNUNET_free (config);
1967       config = NULL;
1968     }
1969   }
1970   sl = GNUNET_new (struct ServiceList);
1971   sl->name = GNUNET_strdup (section);
1972   sl->binary = binary;
1973   sl->config = config;
1974   sl->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
1975   sl->restart_at = GNUNET_TIME_UNIT_FOREVER_ABS;
1976 #if WINDOWS
1977   sl->pipe_control = GNUNET_YES;
1978 #else
1979   if (GNUNET_CONFIGURATION_have_value (cfg,
1980                                        section,
1981                                        "PIPECONTROL"))
1982     sl->pipe_control = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1983                                                              section,
1984                                                              "PIPECONTROL");
1985 #endif
1986   GNUNET_CONTAINER_DLL_insert (running_head,
1987                                running_tail,
1988                                sl);
1989   if (GNUNET_YES ==
1990       GNUNET_CONFIGURATION_get_value_yesno (cfg,
1991                                             section,
1992                                             "FORCESTART"))
1993   {
1994     sl->force_start = GNUNET_YES;
1995     if (GNUNET_YES ==
1996         GNUNET_CONFIGURATION_get_value_yesno (cfg,
1997                                               section,
1998                                               "NOARMBIND"))
1999       return;
2000   }
2001   else
2002   {
2003     if (GNUNET_YES !=
2004         GNUNET_CONFIGURATION_get_value_yesno (cfg,
2005                                               section,
2006                                               "AUTOSTART"))
2007       return;
2008   }
2009   if (0 >= (ret = get_server_addresses (section,
2010                                         cfg,
2011                                         &addrs,
2012                                         &addr_lens)))
2013     return;
2014   /* this will free (or capture) addrs[i] */
2015   for (i = 0; i < ret; i++)
2016     create_listen_socket (addrs[i],
2017                           addr_lens[i],
2018                           sl);
2019   GNUNET_free (addrs);
2020   GNUNET_free (addr_lens);
2021 }
2022
2023
2024 /**
2025  * A client connected, mark as a monitoring client.
2026  *
2027  * @param cls closure
2028  * @param client identification of the client
2029  * @param mq queue to talk to @a client
2030  * @return @a client
2031  */
2032 static void *
2033 client_connect_cb (void *cls,
2034                    struct GNUNET_SERVICE_Client *client,
2035                    struct GNUNET_MQ_Handle *mq)
2036 {
2037   /* All clients are considered to be of the "monitor" kind
2038    * (that is, they don't affect ARM shutdown).
2039    */
2040   GNUNET_SERVICE_client_mark_monitor (client);
2041   return client;
2042 }
2043
2044
2045 /**
2046  * A client disconnected, clean up associated state.
2047  *
2048  * @param cls closure
2049  * @param client identification of the client
2050  * @param app_ctx must match @a client
2051  */
2052 static void
2053 client_disconnect_cb (void *cls,
2054                       struct GNUNET_SERVICE_Client *client,
2055                       void *app_ctx)
2056 {
2057   struct ServiceList *sl;
2058
2059   GNUNET_assert (client == app_ctx);
2060
2061   for (sl = running_head; NULL != sl; sl = sl->next)
2062     if (sl->killing_client == client)
2063       sl->killing_client = NULL;
2064 }
2065
2066
2067 /**
2068  * Handle MONITOR-message.
2069  *
2070  * @param cls identification of the client
2071  * @param message the actual message
2072  * @return #GNUNET_OK to keep the connection open,
2073  *         #GNUNET_SYSERR to close it (signal serious error)
2074  */
2075 static void
2076 handle_monitor (void *cls,
2077                 const struct GNUNET_MessageHeader *message)
2078 {
2079   struct GNUNET_SERVICE_Client *client = cls;
2080
2081   /* FIXME: might want to start by letting monitor know about
2082      services that are already running */
2083   /* Removal is handled by the server implementation, internally. */
2084   GNUNET_notification_context_add (notifier,
2085                                    GNUNET_SERVICE_client_get_mq (client));
2086   broadcast_status ("arm",
2087                     GNUNET_ARM_SERVICE_MONITORING_STARTED,
2088                     client);
2089   GNUNET_SERVICE_client_continue (client);
2090 }
2091
2092
2093 /**
2094  * Process arm requests.
2095  *
2096  * @param cls closure
2097  * @param serv the initialized service
2098  * @param c configuration to use
2099  */
2100 static void
2101 run (void *cls,
2102      const struct GNUNET_CONFIGURATION_Handle *c,
2103      struct GNUNET_SERVICE_Handle *serv)
2104 {
2105   struct ServiceList *sl;
2106
2107   cfg = c;
2108   service = serv;
2109   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
2110                                  NULL);
2111   child_death_task =
2112     GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
2113                                     GNUNET_DISK_pipe_handle (sigpipe,
2114                                                              GNUNET_DISK_PIPE_END_READ),
2115                                     &maint_child_death,
2116                                     NULL);
2117 #if HAVE_WAIT4
2118   if (GNUNET_OK ==
2119       GNUNET_CONFIGURATION_get_value_filename (cfg,
2120                                                "ARM",
2121                                                "RESOURCE_DIAGNOSTICS",
2122                                                &wait_filename))
2123   {
2124     wait_file = fopen (wait_filename,
2125                        "w");
2126     if (NULL == wait_file)
2127     {
2128       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
2129                                 "fopen",
2130                                 wait_filename);
2131     }
2132   }
2133 #endif
2134   if (GNUNET_OK !=
2135       GNUNET_CONFIGURATION_get_value_string (cfg,
2136                                              "ARM",
2137                                              "GLOBAL_PREFIX",
2138                                              &prefix_command))
2139     prefix_command = GNUNET_strdup ("");
2140   else
2141     prefix_command = GNUNET_CONFIGURATION_expand_dollar (cfg,
2142                                                          prefix_command);
2143   if (GNUNET_OK !=
2144       GNUNET_CONFIGURATION_get_value_string (cfg,
2145                                              "ARM",
2146                                              "GLOBAL_POSTFIX",
2147                                              &final_option))
2148     final_option = GNUNET_strdup ("");
2149   else
2150     final_option = GNUNET_CONFIGURATION_expand_dollar (cfg,
2151                                                        final_option);
2152   if (GNUNET_YES ==
2153       GNUNET_CONFIGURATION_get_value_yesno (cfg,
2154                                             "ARM",
2155                                             "USER_ONLY"))
2156   {
2157     GNUNET_break (GNUNET_YES == start_user);
2158     start_system = GNUNET_NO;
2159   }
2160   if (GNUNET_YES ==
2161       GNUNET_CONFIGURATION_get_value_yesno (cfg,
2162                                             "ARM",
2163                                             "SYSTEM_ONLY"))
2164   {
2165     GNUNET_break (GNUNET_YES == start_system);
2166     start_user = GNUNET_NO;
2167   }
2168   GNUNET_CONFIGURATION_iterate_sections (cfg,
2169                                          &setup_service,
2170                                          NULL);
2171
2172   /* start default services... */
2173   for (sl = running_head; NULL != sl; sl = sl->next)
2174     if (GNUNET_YES == sl->force_start)
2175       start_process (sl,
2176                      NULL,
2177                      0);
2178   notifier = GNUNET_notification_context_create (MAX_NOTIFY_QUEUE);
2179 }
2180
2181
2182 /**
2183  * The main function for the arm service.
2184  *
2185  * @param argc number of arguments from the command line
2186  * @param argv command line arguments
2187  * @return 0 ok, 1 on error
2188  */
2189 int
2190 main (int argc,
2191       char *const *argv)
2192 {
2193   int ret;
2194   struct GNUNET_SIGNAL_Context *shc_chld;
2195   struct GNUNET_MQ_MessageHandler handlers[] = {
2196     GNUNET_MQ_hd_var_size (start,
2197                            GNUNET_MESSAGE_TYPE_ARM_START,
2198                            struct GNUNET_ARM_Message,
2199                            NULL),
2200     GNUNET_MQ_hd_var_size (stop,
2201                            GNUNET_MESSAGE_TYPE_ARM_STOP,
2202                            struct GNUNET_ARM_Message,
2203                            NULL),
2204     GNUNET_MQ_hd_fixed_size (monitor,
2205                              GNUNET_MESSAGE_TYPE_ARM_MONITOR,
2206                              struct GNUNET_MessageHeader,
2207                              NULL),
2208     GNUNET_MQ_hd_fixed_size (list,
2209                              GNUNET_MESSAGE_TYPE_ARM_LIST,
2210                              struct GNUNET_ARM_Message,
2211                              NULL),
2212     GNUNET_MQ_hd_fixed_size (test,
2213                              GNUNET_MESSAGE_TYPE_ARM_TEST,
2214                              struct GNUNET_MessageHeader,
2215                              NULL),
2216     GNUNET_MQ_handler_end ()
2217   };
2218
2219   sigpipe = GNUNET_DISK_pipe (GNUNET_NO,
2220                               GNUNET_NO,
2221                               GNUNET_NO,
2222                               GNUNET_NO);
2223   GNUNET_assert (NULL != sigpipe);
2224   shc_chld =
2225     GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD,
2226                                    &sighandler_child_death);
2227   ret = GNUNET_SERVICE_ruN_ (argc,
2228                              argv,
2229                              "arm",
2230                              GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN,
2231                              &run,
2232                              &client_connect_cb,
2233                              &client_disconnect_cb,
2234                              NULL,
2235                              handlers);
2236 #if HAVE_WAIT4
2237   if (NULL != wait_file)
2238   {
2239     fclose (wait_file);
2240     wait_file = NULL;
2241   }
2242   if (NULL != wait_filename)
2243   {
2244     GNUNET_free (wait_filename);
2245     wait_filename = NULL;
2246   }
2247 #endif
2248   GNUNET_SIGNAL_handler_uninstall (shc_chld);
2249   shc_chld = NULL;
2250   GNUNET_DISK_pipe_close (sigpipe);
2251   sigpipe = NULL;
2252   return ret;
2253 }
2254
2255
2256 #if defined(LINUX) && defined(__GLIBC__)
2257 #include <malloc.h>
2258
2259 /**
2260  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
2261  */
2262 void __attribute__ ((constructor)) GNUNET_ARM_memory_init ()
2263 {
2264   mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2265   mallopt (M_TOP_PAD, 1 * 1024);
2266   malloc_trim (0);
2267 }
2268 #endif
2269
2270
2271 /* end of gnunet-service-arm.c */