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