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