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