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