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