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