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