- fix 2699
[oweals/gnunet.git] / src / arm / gnunet-service-arm.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, 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 /**
33  * List of our services.
34  */
35 struct ServiceList;
36
37
38 /**
39  * Record with information about a listen socket we have open.
40  */
41 struct ServiceListeningInfo
42 {
43   /**
44    * This is a linked list.
45    */
46   struct ServiceListeningInfo *next;
47
48   /**
49    * This is a linked list.
50    */
51   struct ServiceListeningInfo *prev;
52
53   /**
54    * Address this socket is listening on.
55    */
56   struct sockaddr *service_addr;
57
58   /**
59    * Service this listen socket is for.
60    */
61   struct ServiceList *sl;
62
63   /**
64    * Number of bytes in 'service_addr'
65    */
66   socklen_t service_addr_len;
67
68   /**
69    * Our listening socket.
70    */
71   struct GNUNET_NETWORK_Handle *listen_socket;
72
73   /**
74    * Task doing the accepting.
75    */
76   GNUNET_SCHEDULER_TaskIdentifier accept_task;
77
78 };
79
80
81 /**
82  * List of our services.
83  */
84 struct ServiceList
85 {
86   /**
87    * This is a doubly-linked list.
88    */
89   struct ServiceList *next;
90
91   /**
92    * This is a doubly-linked list.
93    */
94   struct ServiceList *prev;
95
96   /**
97    * Linked list of listen sockets associated with this service.
98    */
99   struct ServiceListeningInfo *listen_head;
100
101   /**
102    * Linked list of listen sockets associated with this service.
103    */
104   struct ServiceListeningInfo *listen_tail;
105
106   /**
107    * Name of the service.
108    */
109   char *name;
110
111   /**
112    * Name of the binary used.
113    */
114   char *binary;
115
116   /**
117    * Name of the configuration file used.
118    */
119   char *config;
120
121   /**
122    * Client to notify upon kill completion (waitpid), NULL
123    * if we should simply restart the process.
124    */
125   struct GNUNET_SERVER_Client *killing_client;
126
127   /**
128    * Process structure pointer of the child.
129    */
130   struct GNUNET_OS_Process *proc;
131
132   /**
133    * Process exponential backoff time
134    */
135   struct GNUNET_TIME_Relative backoff;
136
137   /**
138    * Absolute time at which the process is scheduled to restart in case of death
139    */
140   struct GNUNET_TIME_Absolute restart_at;
141
142   /**
143    * Time we asked the service to shut down (used to calculate time it took
144    * the service to terminate).
145    */
146   struct GNUNET_TIME_Absolute killed_at;
147
148   /**
149    * Is this service to be started by default (or did a client tell us explicitly
150    * to start it)?  GNUNET_NO if the service is started only upon 'accept' on a
151    * listen socket or possibly explicitly by a client changing the value.
152    */
153   int is_default;
154
155   /**
156    * Should we use pipes to signal this process? (YES for Java binaries and if we
157    * are on Windoze).
158    */
159   int pipe_control;
160 };
161
162 /**
163  * List of running services.
164  */
165 static struct ServiceList *running_head;
166
167 /**
168  * List of running services.
169  */
170 static struct ServiceList *running_tail;
171
172 /**
173  * Our configuration
174  */
175 static const struct GNUNET_CONFIGURATION_Handle *cfg;
176
177 /**
178  * Command to prepend to each actual command.
179  */
180 static char *prefix_command;
181
182 /**
183  * Option to append to each actual command.
184  */
185 static char *final_option;
186
187 /**
188  * ID of task called whenever we get a SIGCHILD.
189  */
190 static GNUNET_SCHEDULER_TaskIdentifier child_death_task;
191
192 /**
193  * ID of task called whenever the timeout for restarting a child
194  * expires.
195  */
196 static GNUNET_SCHEDULER_TaskIdentifier child_restart_task;
197
198 /**
199  * Pipe used to communicate shutdown via signal.
200  */
201 static struct GNUNET_DISK_PipeHandle *sigpipe;
202
203 /**
204  * Are we in shutdown mode?
205  */
206 static int in_shutdown;
207
208 /**
209  * Handle to our server instance.  Our server is a bit special in that
210  * its service is not immediately stopped once we get a shutdown
211  * request (since we need to continue service until all of our child
212  * processes are dead).  This handle is used to shut down the server
213  * (and thus trigger process termination) once all child processes are
214  * also dead.  A special option in the ARM configuration modifies the
215  * behaviour of the service implementation to not do the shutdown
216  * immediately.
217  */
218 static struct GNUNET_SERVER_Handle *server;
219
220
221 #include "do_start_process.c"
222
223
224 /**
225  * Actually start the process for the given service.
226  *
227  * @param sl identifies service to start
228  */
229 static void
230 start_process (struct ServiceList *sl)
231 {
232   char *loprefix;
233   char *options;
234   char *optpos;
235   char *optend;
236   const char *next;
237   int use_debug;
238   char b;
239   char *val;
240   struct ServiceListeningInfo *sli;
241   SOCKTYPE *lsocks;
242   unsigned int ls;
243   char *binary;
244
245   /* calculate listen socket list */
246   lsocks = NULL;
247   ls = 0;
248   for (sli = sl->listen_head; NULL != sli; sli = sli->next)
249     {
250       GNUNET_array_append (lsocks, ls,
251                            GNUNET_NETWORK_get_fd (sli->listen_socket));
252       if (sli->accept_task != GNUNET_SCHEDULER_NO_TASK)
253         {
254           GNUNET_SCHEDULER_cancel (sli->accept_task);
255           sli->accept_task = GNUNET_SCHEDULER_NO_TASK;
256         }
257     }
258 #if WINDOWS
259   GNUNET_array_append (lsocks, ls, INVALID_SOCKET);
260 #else
261   GNUNET_array_append (lsocks, ls, -1);
262 #endif
263
264   /* obtain configuration */
265   if (GNUNET_OK !=
266       GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "PREFIX",
267                                              &loprefix))
268     loprefix = GNUNET_strdup (prefix_command);
269   if (GNUNET_OK !=
270       GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "OPTIONS",
271                                              &options))
272     {
273       options = GNUNET_strdup (final_option);
274       if (NULL == strstr (options, "%"))
275         {
276           /* replace '{}' with service name */
277           while (NULL != (optpos = strstr (options, "{}")))
278             {
279               optpos[0] = '%';
280               optpos[1] = 's';
281               GNUNET_asprintf (&optpos, options, sl->name);
282               GNUNET_free (options);
283               options = optpos;
284             }
285           /* replace '$PATH' with value associated with "PATH" */
286           while (NULL != (optpos = strstr (options, "$")))
287             {
288               optend = optpos + 1;
289               while (isupper ((unsigned char) *optend))
290                 optend++;
291               b = *optend;
292               if ('\0' == b)
293                 next = "";
294               else
295                 next = optend + 1;
296               *optend = '\0';
297               if (GNUNET_OK !=
298                   GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
299                                                          optpos + 1, &val))
300                 val = GNUNET_strdup ("");
301               *optpos = '\0';
302               GNUNET_asprintf (&optpos, "%s%s%c%s", options, val, b, next);
303               GNUNET_free (options);
304               GNUNET_free (val);
305               options = optpos;
306             }
307         }
308     }
309   use_debug = GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name, "DEBUG");
310
311   /* actually start process */
312   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
313               "Starting service `%s' using binary `%s' and configuration `%s'\n",
314               sl->name, sl->binary, sl->config);
315   binary = GNUNET_OS_get_libexec_binary_path (sl->binary);
316   GNUNET_assert (NULL == sl->proc);
317   if (GNUNET_YES == use_debug)
318   {
319     if (NULL == sl->config)
320       sl->proc =
321         do_start_process (sl->pipe_control, GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
322                           lsocks, loprefix, binary, "-L",
323                           "DEBUG", options, NULL);
324     else
325       sl->proc =
326         do_start_process (sl->pipe_control, GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
327                           lsocks, loprefix, binary, "-c", sl->config, "-L",
328                           "DEBUG", options, NULL);
329   }
330   else
331   {
332     if (NULL == sl->config)
333       sl->proc =
334         do_start_process (sl->pipe_control, GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
335                           lsocks, loprefix, binary, 
336                           options, NULL);
337     else
338       sl->proc =
339         do_start_process (sl->pipe_control, GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
340                           lsocks, loprefix, binary, "-c", sl->config,
341                           options, NULL);
342   }
343   GNUNET_free (binary);
344   if (sl->proc == NULL)
345     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to start service `%s'\n"),
346                 sl->name);
347   else
348     GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting service `%s'\n"),
349                 sl->name);
350   /* clean up */
351   GNUNET_free (loprefix);
352   GNUNET_free (options);
353   GNUNET_array_grow (lsocks, ls, 0);
354 }
355
356
357 /**
358  * Transmit a status result message.
359  *
360  * @param cls pointer to "unit16_t*" with message type
361  * @param size number of bytes available in buf
362  * @param buf where to copy the message, NULL on error
363  * @return number of bytes copied to buf
364  */
365 static size_t
366 write_result (void *cls, size_t size, void *buf)
367 {
368   enum GNUNET_ARM_ProcessStatus *res = cls;
369   struct GNUNET_ARM_ResultMessage *msg;
370
371   if (buf == NULL)
372   {
373     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
374                 _("Could not send status result to client\n"));
375     return 0;                   /* error, not much we can do */
376   }
377   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
378               "Sending status response %u to client\n", (unsigned int) *res);
379   GNUNET_assert (size >= sizeof (struct GNUNET_ARM_ResultMessage));
380   msg = buf;
381   msg->header.size = htons (sizeof (struct GNUNET_ARM_ResultMessage));
382   msg->header.type = htons (GNUNET_MESSAGE_TYPE_ARM_RESULT);
383   msg->status = htonl ((uint32_t) (*res));
384   GNUNET_free (res);
385   return sizeof (struct GNUNET_ARM_ResultMessage);
386 }
387
388 /**
389  * Transmit the list of running services.
390  * 
391  * @param cls pointer to struct GNUNET_ARM_ListResultMessage with the message
392  * @param size number of bytes available in buf
393  * @param buf where to copy the message, NULL on error
394  * @return number of bytes copied to buf
395  */
396 static size_t
397 write_list_result (void *cls, size_t size, void *buf)
398 {
399   struct GNUNET_ARM_ListResultMessage *msg = cls;
400   struct GNUNET_ARM_ListResultMessage *rslt;
401   size_t rslt_size;
402   
403   if (buf == NULL)
404   {
405     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
406                 _("Could not send list result to client\n"));
407     return 0;                   /* error, not much we can do */
408   }
409   
410   GNUNET_assert (size >= msg->header.size);
411   rslt = buf;
412   rslt->header.size = htons (msg->header.size);
413   rslt->header.type = htons (msg->header.type);
414   rslt->count = htons (msg->count);
415   
416   size_t list_size = msg->header.size 
417                      - sizeof (struct GNUNET_ARM_ListResultMessage);  
418   memcpy (&rslt[1], &msg[1], list_size);
419
420   rslt_size = msg->header.size;
421   GNUNET_free (msg);
422   return rslt_size;
423 }
424
425
426 /**
427  * Signal our client that we will start or stop the
428  * service.
429  *
430  * @param client who is being signalled
431  * @param name name of the service
432  * @param result message type to send
433  * @return NULL if it was not found
434  */
435 static void
436 signal_result (struct GNUNET_SERVER_Client *client, const char *name,
437                enum GNUNET_ARM_ProcessStatus result)
438 {
439   enum GNUNET_ARM_ProcessStatus *res;
440
441   if (NULL == client)
442     return;
443   /* FIXME: this is not super-clean yet... */
444   res = GNUNET_malloc (sizeof (enum GNUNET_ARM_ProcessStatus));
445   *res = result;
446   GNUNET_SERVER_notify_transmit_ready (client,
447                                        sizeof (struct
448                                                GNUNET_ARM_ResultMessage),
449                                        GNUNET_TIME_UNIT_FOREVER_REL,
450                                        &write_result, res);
451   GNUNET_SERVER_receive_done (client, GNUNET_OK);
452 }
453
454
455 /**
456  * Find the process with the given service
457  * name in the given list and return it.
458  *
459  * @param name which service entry to look up
460  * @return NULL if it was not found
461  */
462 static struct ServiceList *
463 find_service (const char *name)
464 {
465   struct ServiceList *sl;
466
467   sl = running_head;
468   while (sl != NULL)
469     {
470       if (0 == strcasecmp (sl->name, name))
471         return sl;
472       sl = sl->next;
473     }
474   return NULL;
475 }
476
477
478 /**
479  * First connection has come to the listening socket associated with the service,
480  * create the service in order to relay the incoming connection to it
481  *
482  * @param cls callback data, struct ServiceListeningInfo describing a listen socket
483  * @param tc context
484  */
485 static void
486 accept_connection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
487 {
488   struct ServiceListeningInfo *sli = cls;
489   struct ServiceList *sl = sli->sl;
490
491   sli->accept_task = GNUNET_SCHEDULER_NO_TASK;
492   GNUNET_assert (GNUNET_NO == in_shutdown);
493   if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
494     return;
495   start_process (sl);
496 }
497
498
499 /**
500  * Creating a listening socket for each of the service's addresses and
501  * wait for the first incoming connection to it
502  *
503  * @param sa address associated with the service
504  * @param addr_len length of sa
505  * @param sl service entry for the service in question
506  */
507 static void
508 create_listen_socket (struct sockaddr *sa, socklen_t addr_len,
509                       struct ServiceList *sl)
510 {
511   static int on = 1;
512   struct GNUNET_NETWORK_Handle *sock;
513   struct ServiceListeningInfo *sli;
514
515   switch (sa->sa_family)
516     {
517     case AF_INET:
518       sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
519       break;
520     case AF_INET6:
521       sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
522       break;
523     case AF_UNIX:
524       if (strcmp (GNUNET_a2s (sa, addr_len), "@") == 0) /* Do not bind to blank UNIX path! */
525         return;
526       sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
527       break;
528     default:
529       GNUNET_break (0);
530       sock = NULL;
531       errno = EAFNOSUPPORT;
532       break;
533     }
534   if (NULL == sock)
535     {
536       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
537                   _("Unable to create socket for service `%s': %s\n"),
538                   sl->name, STRERROR (errno));
539       GNUNET_free (sa);
540       return;
541     }
542   if (GNUNET_NETWORK_socket_setsockopt
543       (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
544     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
545                          "setsockopt");
546 #ifdef IPV6_V6ONLY
547   if ((sa->sa_family == AF_INET6) &&
548       (GNUNET_NETWORK_socket_setsockopt
549        (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK))
550     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
551                          "setsockopt");
552 #endif
553
554   if (GNUNET_NETWORK_socket_bind
555       (sock, (const struct sockaddr *) sa, addr_len) != GNUNET_OK)
556     {
557       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
558                   _
559                   ("Unable to bind listening socket for service `%s' to address `%s': %s\n"),
560                   sl->name, GNUNET_a2s (sa, addr_len), STRERROR (errno));
561       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
562       GNUNET_free (sa);
563       return;
564     }
565   if (GNUNET_NETWORK_socket_listen (sock, 5) != GNUNET_OK)
566     {
567       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
568       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
569       GNUNET_free (sa);
570       return;
571     }
572   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
573               _("ARM now monitors connections to service `%s' at `%s'\n"),
574               sl->name, GNUNET_a2s (sa, addr_len));
575   sli = GNUNET_malloc (sizeof (struct ServiceListeningInfo));
576   sli->service_addr = sa;
577   sli->service_addr_len = addr_len;
578   sli->listen_socket = sock;
579   sli->sl = sl;
580   sli->accept_task =
581     GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sock,
582                                    &accept_connection, sli);
583   GNUNET_CONTAINER_DLL_insert (sl->listen_head, sl->listen_tail, sli);
584 }
585
586
587 /**
588  * Remove and free an entry in the service list.  Listen sockets
589  * must have already been cleaned up.  Only to be called during shutdown.
590  *
591  * @param sl entry to free
592  */
593 static void
594 free_service (struct ServiceList *sl)
595 {
596   GNUNET_assert (GNUNET_YES == in_shutdown);
597   GNUNET_CONTAINER_DLL_remove (running_head, running_tail, sl);
598   GNUNET_assert (NULL == sl->listen_head);
599   GNUNET_free_non_null (sl->config);
600   GNUNET_free_non_null (sl->binary);
601   GNUNET_free (sl->name);
602   GNUNET_free (sl);
603 }
604
605
606 /**
607  * Handle START-message.
608  *
609  * @param cls closure (always NULL)
610  * @param client identification of the client
611  * @param message the actual message
612  * @return GNUNET_OK to keep the connection open,
613  *         GNUNET_SYSERR to close it (signal serious error)
614  */
615 static void
616 handle_start (void *cls, struct GNUNET_SERVER_Client *client,
617               const struct GNUNET_MessageHeader *message)
618 {
619   const char *servicename;
620   struct ServiceList *sl;
621   uint16_t size;
622   
623   size = ntohs (message->size);
624   size -= sizeof (struct GNUNET_MessageHeader);
625   servicename = (const char *) &message[1];
626   if ((size == 0) || (servicename[size - 1] != '\0'))
627     {
628       GNUNET_break (0);
629       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
630       return;
631     }
632   if (GNUNET_YES == in_shutdown)
633     {
634       signal_result (client, servicename, GNUNET_ARM_PROCESS_SHUTDOWN);
635       return;
636     }
637   sl = find_service (servicename);
638   if (NULL == sl)
639     {
640       signal_result (client, servicename, GNUNET_ARM_PROCESS_UNKNOWN);
641       return;
642     }
643   sl->is_default = GNUNET_YES;
644   if (sl->proc != NULL)
645     {
646       signal_result (client, servicename, GNUNET_ARM_PROCESS_ALREADY_RUNNING);
647       return;
648     }
649   start_process (sl);
650   signal_result (client, servicename, GNUNET_ARM_PROCESS_STARTING);
651 }
652
653
654 /**
655  * Handle STOP-message.
656  *
657  * @param cls closure (always NULL)
658  * @param client identification of the client
659  * @param message the actual message
660  * @return GNUNET_OK to keep the connection open,
661  *         GNUNET_SYSERR to close it (signal serious error)
662  */
663 static void
664 handle_stop (void *cls, struct GNUNET_SERVER_Client *client,
665              const struct GNUNET_MessageHeader *message)
666 {
667   struct ServiceList *sl;
668   const char *servicename;
669   uint16_t size;
670
671   size = ntohs (message->size);
672   size -= sizeof (struct GNUNET_MessageHeader);
673   servicename = (const char *) &message[1];
674   if ((size == 0) || (servicename[size - 1] != '\0'))
675     {
676       GNUNET_break (0);
677       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
678       return;
679     }
680   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
681               _("Preparing to stop `%s'\n"), servicename);
682   sl = find_service (servicename);
683   if (sl == NULL)
684     {
685       signal_result (client, servicename, GNUNET_ARM_PROCESS_UNKNOWN);
686       return;
687     }
688   sl->is_default = GNUNET_NO;
689   if (GNUNET_YES == in_shutdown)
690     {
691       /* shutdown in progress */
692       signal_result (client, servicename, GNUNET_ARM_PROCESS_SHUTDOWN);
693       return;
694     }
695   if (sl->killing_client != NULL)
696     {
697       /* killing already in progress */
698       signal_result (client, servicename,
699                      GNUNET_ARM_PROCESS_ALREADY_STOPPING);
700       return;
701     }
702   if (sl->proc == NULL)
703     {
704       /* process is down */
705       signal_result (client, servicename, GNUNET_ARM_PROCESS_ALREADY_DOWN);
706       return;
707     }
708   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
709               "Sending kill signal to service `%s', waiting for process to die.\n",
710               servicename);
711   sl->killed_at = GNUNET_TIME_absolute_get ();
712   if (0 != GNUNET_OS_process_kill (sl->proc, SIGTERM))
713     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
714   sl->killing_client = client;
715   GNUNET_SERVER_client_keep (client);
716 }
717
718 /**
719  * Handle LIST-message.
720  *
721  * @param cls closure (always NULL)
722  * @param client identification of the client
723  * @param message the actual message
724  */
725 static void
726 handle_list (void *cls, struct GNUNET_SERVER_Client *client,
727              const struct GNUNET_MessageHeader *message)
728 {
729   struct GNUNET_ARM_ListResultMessage *msg;
730   size_t string_list_size;
731   size_t total_size;
732   struct ServiceList *sl;
733   uint16_t count;
734   
735   if (NULL == client)
736     return;
737   
738   count = 0;
739   string_list_size = 0;
740   /* first count the running processes get their name's size */
741   for (sl = running_head; sl != NULL; sl = sl->next)
742   {
743     if (sl->proc != NULL)
744     {
745       string_list_size += strlen (sl->name);
746       string_list_size += strlen (sl->binary);
747       string_list_size += 4;
748       count++;
749     }
750   }
751   total_size = sizeof (struct GNUNET_ARM_ListResultMessage) 
752                + string_list_size;
753   msg = GNUNET_malloc (total_size);
754   msg->header.size = total_size;
755   msg->header.type = GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT;
756   msg->count = count;
757   
758   char *pos = (char *)&msg[1];
759   for (sl = running_head; sl != NULL; sl = sl->next) 
760   {
761     if (sl->proc != NULL)
762     {
763       size_t s = strlen (sl->name) + strlen (sl->binary) + 4;
764       GNUNET_snprintf(pos, s, "%s (%s)", sl->name, sl->binary);
765       pos += s;
766     }
767   }
768   
769   GNUNET_SERVER_notify_transmit_ready (client,
770                                        msg->header.size,
771                                        GNUNET_TIME_UNIT_FOREVER_REL,
772                                        &write_list_result, msg);
773   GNUNET_SERVER_receive_done (client, GNUNET_OK);
774 }
775
776 /**
777  * We are done with everything.  Stop remaining
778  * tasks, signal handler and the server.
779  */
780 static void
781 do_shutdown ()
782 {
783   if (NULL != server)
784     {
785       GNUNET_SERVER_destroy (server);
786       server = NULL;
787     }
788   if (GNUNET_SCHEDULER_NO_TASK != child_death_task)
789     {
790       GNUNET_SCHEDULER_cancel (child_death_task);
791       child_death_task = GNUNET_SCHEDULER_NO_TASK;
792     }
793 }
794
795
796 /**
797  * Task run for shutdown.
798  *
799  * @param cls closure, NULL if we need to self-restart
800  * @param tc context
801  */
802 static void
803 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
804 {
805   struct ServiceList *pos;
806   struct ServiceList *nxt;
807   struct ServiceListeningInfo *sli;
808
809   if (GNUNET_SCHEDULER_NO_TASK != child_restart_task)
810   {
811     GNUNET_SCHEDULER_cancel (child_restart_task);
812     child_restart_task = GNUNET_SCHEDULER_NO_TASK;
813   }
814   in_shutdown = GNUNET_YES;
815   /* first, stop listening */
816   for (pos = running_head; NULL != pos; pos = pos->next)
817   {
818     while (NULL != (sli = pos->listen_head))
819       {
820         GNUNET_CONTAINER_DLL_remove (pos->listen_head,
821                                      pos->listen_tail, sli);
822         if (sli->accept_task != GNUNET_SCHEDULER_NO_TASK)
823           {
824             GNUNET_SCHEDULER_cancel (sli->accept_task);
825             sli->accept_task = GNUNET_SCHEDULER_NO_TASK;
826           }
827         GNUNET_break (GNUNET_OK ==
828                       GNUNET_NETWORK_socket_close (sli->listen_socket));
829         GNUNET_free (sli->service_addr);
830         GNUNET_free (sli);
831       }
832   }
833   /* then, shutdown all existing service processes */
834   nxt = running_head;
835   while (NULL != (pos = nxt))
836   {
837     nxt = pos->next;
838     if (pos->proc != NULL)
839     {
840       GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping service `%s'\n",
841                   pos->name);
842       pos->killed_at = GNUNET_TIME_absolute_get ();
843       if (0 != GNUNET_OS_process_kill (pos->proc, SIGTERM))
844         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
845     }
846     else
847     {
848       free_service (pos);
849     }
850   }
851   /* finally, should all service processes be already gone, terminate for real */
852   if (running_head == NULL)
853     do_shutdown ();
854 }
855
856
857 /**
858  * Task run whenever it is time to restart a child that died.
859  *
860  * @param cls closure, always NULL
861  * @param tc context
862  */
863 static void
864 delayed_restart_task (void *cls,
865                       const struct GNUNET_SCHEDULER_TaskContext *tc)
866 {
867   struct ServiceList *sl;
868   struct GNUNET_TIME_Relative lowestRestartDelay;
869   struct ServiceListeningInfo *sli;
870
871   child_restart_task = GNUNET_SCHEDULER_NO_TASK;
872   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
873     return;
874   GNUNET_assert (GNUNET_NO == in_shutdown);
875   lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL;
876
877   /* check for services that need to be restarted due to
878    * configuration changes or because the last restart failed */
879   for (sl = running_head; NULL != sl; sl = sl->next)
880   {
881     if (NULL != sl->proc)
882       continue;
883     /* service is currently not running */
884     if (GNUNET_TIME_absolute_get_remaining (sl->restart_at).rel_value ==
885         0)
886     {
887       /* restart is now allowed */
888       if (sl->is_default)
889       {
890         /* process should run by default, start immediately */
891         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
892                     _("Restarting service `%s'.\n"), sl->name);
893         start_process (sl);
894       }
895       else
896       {
897         /* process is run on-demand, ensure it is re-started if there is demand */
898         for (sli = sl->listen_head; NULL != sli; sli = sli->next)
899           if (GNUNET_SCHEDULER_NO_TASK == sli->accept_task)
900           {
901             /* accept was actually paused, so start it again */
902             sli->accept_task =
903               GNUNET_SCHEDULER_add_read_net
904               (GNUNET_TIME_UNIT_FOREVER_REL, sli->listen_socket,
905                &accept_connection, sli);
906           }
907       }
908     }
909     else
910     {
911       /* update calculation for earliest time to reactivate a service */
912       lowestRestartDelay =
913         GNUNET_TIME_relative_min (lowestRestartDelay,
914                                   GNUNET_TIME_absolute_get_remaining
915                                   (sl->restart_at));
916     }
917   }
918   if (lowestRestartDelay.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
919   {
920     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
921                 "Will restart process in %s\n",
922                 GNUNET_STRINGS_relative_time_to_string (lowestRestartDelay, GNUNET_YES));
923     child_restart_task =
924       GNUNET_SCHEDULER_add_delayed_with_priority (lowestRestartDelay,
925                                                   GNUNET_SCHEDULER_PRIORITY_IDLE, 
926                                                   &delayed_restart_task, NULL);
927   }
928 }
929
930
931 /**
932  * Task triggered whenever we receive a SIGCHLD (child
933  * process died).
934  *
935  * @param cls closure, NULL if we need to self-restart
936  * @param tc context
937  */
938 static void
939 maint_child_death (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
940 {
941   struct ServiceList *pos;
942   struct ServiceList *next;
943   struct ServiceListeningInfo *sli;
944   const char *statstr;
945   int statcode;
946   int ret;
947   char c[16];
948   enum GNUNET_OS_ProcessStatusType statusType;
949   unsigned long statusCode;
950   const struct GNUNET_DISK_FileHandle *pr;
951
952   pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
953   child_death_task = GNUNET_SCHEDULER_NO_TASK;
954   if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
955     {
956       /* shutdown scheduled us, ignore! */
957       child_death_task =
958         GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
959                                         pr, &maint_child_death, NULL);
960       return;
961     }
962   /* consume the signal */
963   GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
964
965   /* check for services that died (WAITPID) */
966   next = running_head;
967   while (NULL != (pos = next))
968     {
969       next = pos->next;
970
971       if (pos->proc == NULL)
972       {
973         if (GNUNET_YES == in_shutdown)
974           free_service (pos);
975         continue;
976       }
977       if ((GNUNET_SYSERR ==
978            (ret =
979             GNUNET_OS_process_status (pos->proc, &statusType, &statusCode)))
980           || ((ret == GNUNET_NO) || (statusType == GNUNET_OS_PROCESS_STOPPED)
981               || (statusType == GNUNET_OS_PROCESS_RUNNING)))
982         continue;
983       if (statusType == GNUNET_OS_PROCESS_EXITED)
984       {
985         statstr = _( /* process termination method */ "exit");
986         statcode = statusCode;
987       }
988       else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
989       {
990         statstr = _( /* process termination method */ "signal");
991         statcode = statusCode;
992       }
993       else
994       {
995         statstr = _( /* process termination method */ "unknown");
996         statcode = 0;
997       }
998       if (0 != pos->killed_at.abs_value)
999       {
1000         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1001                     _("Service `%s' took %s to terminate\n"),
1002                     pos->name,
1003                     GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->killed_at), GNUNET_YES));
1004       }
1005       GNUNET_OS_process_destroy (pos->proc);
1006       pos->proc = NULL;
1007       if (NULL != pos->killing_client)
1008         {
1009           signal_result (pos->killing_client, pos->name,
1010                          GNUNET_ARM_PROCESS_DOWN);
1011           GNUNET_SERVER_client_drop (pos->killing_client);
1012           pos->killing_client = NULL;
1013           /* process can still be re-started on-demand, ensure it is re-started if there is demand */
1014           for (sli = pos->listen_head; NULL != sli; sli = sli->next)
1015             {
1016               GNUNET_break (GNUNET_SCHEDULER_NO_TASK == sli->accept_task);
1017               sli->accept_task =
1018                 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1019                                                sli->listen_socket,
1020                                                &accept_connection, sli);
1021             }
1022           continue;
1023         }
1024       if (GNUNET_YES != in_shutdown)
1025         {
1026           if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0))
1027             {
1028               /* process terminated normally, allow restart at any time */
1029               pos->restart_at.abs_value = 0;
1030             }
1031           else
1032             {
1033               if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1034                 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1035                             _
1036                             ("Service `%s' terminated with status %s/%d, will restart in %llu ms\n"),
1037                             pos->name, statstr, statcode, pos->backoff.rel_value);
1038               /* schedule restart */
1039               pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff);
1040               pos->backoff = GNUNET_TIME_STD_BACKOFF (pos->backoff);
1041             }
1042           if (GNUNET_SCHEDULER_NO_TASK != child_restart_task)
1043             GNUNET_SCHEDULER_cancel (child_restart_task);
1044           child_restart_task =
1045             GNUNET_SCHEDULER_add_with_priority
1046             (GNUNET_SCHEDULER_PRIORITY_IDLE, 
1047              &delayed_restart_task, NULL);
1048         }
1049       else
1050         {
1051           free_service (pos);
1052         }
1053     }
1054   child_death_task =
1055     GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1056                                     pr, &maint_child_death, NULL);
1057   if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
1058     do_shutdown ();
1059 }
1060
1061
1062 /**
1063  * Handler for SHUTDOWN message.
1064  *
1065  * @param cls closure (refers to service)
1066  * @param client identification of the client
1067  * @param message the actual message
1068  */
1069 static void
1070 handle_shutdown (void *cls, struct GNUNET_SERVER_Client *client,
1071                  const struct GNUNET_MessageHeader *message)
1072 {
1073   GNUNET_SCHEDULER_shutdown ();
1074   GNUNET_SERVER_client_persist_ (client);
1075 }
1076
1077
1078 /**
1079  * Signal handler called for SIGCHLD.  Triggers the
1080  * respective handler by writing to the trigger pipe.
1081  */
1082 static void
1083 sighandler_child_death ()
1084 {
1085   static char c;
1086   int old_errno = errno;        /* back-up errno */
1087
1088   GNUNET_break (1 ==
1089                 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
1090                                         (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
1091                                         &c, sizeof (c)));
1092   errno = old_errno;            /* restore errno */
1093 }
1094
1095
1096 /**
1097  * Setup our service record for the given section in the configuration file
1098  * (assuming the section is for a service).
1099  *
1100  * @param cls unused
1101  * @param section a section in the configuration file
1102  * @return GNUNET_OK (continue)
1103  */
1104 static void
1105 setup_service (void *cls, const char *section)
1106 {
1107   struct ServiceList *sl;
1108   char *binary;
1109   char *config;
1110   struct stat sbuf;
1111   struct sockaddr **addrs;
1112   socklen_t *addr_lens;
1113   int ret;
1114   unsigned int i;
1115
1116   if (strcasecmp (section, "arm") == 0)
1117     return;
1118   if (GNUNET_OK !=
1119       GNUNET_CONFIGURATION_get_value_string (cfg, section, "BINARY", &binary))
1120     {
1121       /* not a service section */
1122       return;
1123     }
1124   sl = find_service (section);
1125   if (NULL != sl)
1126   {
1127     /* got the same section twice!? */
1128     GNUNET_break (0);
1129     return;
1130   }
1131   config = NULL;
1132   if (( (GNUNET_OK !=
1133          GNUNET_CONFIGURATION_get_value_filename (cfg, section, "CONFIG",
1134                                                   &config)) &&
1135         (GNUNET_OK !=
1136          GNUNET_CONFIGURATION_get_value_filename (cfg, "PATHS", "DEFAULTCONFIG",
1137                                                   &config)) ) ||
1138       (0 != STAT (config, &sbuf)))
1139   {
1140     if (NULL != config)
1141     {
1142       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, 
1143                                  section, "CONFIG",
1144                                  STRERROR (errno));
1145       GNUNET_free (config);
1146       config = NULL;
1147     }
1148   }
1149   sl = GNUNET_malloc (sizeof (struct ServiceList));
1150   sl->name = GNUNET_strdup (section);
1151   sl->binary = binary;
1152   sl->config = config;
1153   sl->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
1154   sl->restart_at = GNUNET_TIME_UNIT_FOREVER_ABS;
1155 #if WINDOWS
1156   sl->pipe_control = GNUNET_YES;
1157 #else
1158   if (GNUNET_CONFIGURATION_have_value (cfg, section, "PIPECONTROL"))
1159     sl->pipe_control = GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "PIPECONTROL");
1160 #endif  
1161   GNUNET_CONTAINER_DLL_insert (running_head, running_tail, sl);
1162   if (GNUNET_YES !=
1163       GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "AUTOSTART"))
1164     return;
1165   if (0 >= (ret = GNUNET_SERVICE_get_server_addresses (section, cfg,
1166                                                        &addrs, &addr_lens)))
1167     return;
1168   /* this will free (or capture) addrs[i] */
1169   for (i = 0; i < ret; i++)
1170     create_listen_socket (addrs[i], addr_lens[i], sl);
1171   GNUNET_free (addrs);
1172   GNUNET_free (addr_lens);
1173 }
1174
1175
1176 /**
1177  * Process arm requests.
1178  *
1179  * @param cls closure
1180  * @param serv the initialized server
1181  * @param c configuration to use
1182  */
1183 static void
1184 run (void *cls, struct GNUNET_SERVER_Handle *serv,
1185      const struct GNUNET_CONFIGURATION_Handle *c)
1186 {
1187   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1188     {&handle_start, NULL, GNUNET_MESSAGE_TYPE_ARM_START, 0},
1189     {&handle_stop, NULL, GNUNET_MESSAGE_TYPE_ARM_STOP, 0},
1190     {&handle_shutdown, NULL, GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN,
1191      sizeof (struct GNUNET_MessageHeader)},
1192     {&handle_list, NULL, GNUNET_MESSAGE_TYPE_ARM_LIST, 
1193      sizeof (struct GNUNET_MessageHeader)},
1194     {NULL, NULL, 0, 0}
1195   };
1196   char *defaultservices;
1197   const char *pos;
1198   struct ServiceList *sl;
1199
1200   cfg = c;
1201   server = serv;
1202   GNUNET_assert (serv != NULL);
1203   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1204                                 NULL);
1205   child_death_task =
1206     GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1207                                     GNUNET_DISK_pipe_handle (sigpipe,
1208                                                              GNUNET_DISK_PIPE_END_READ),
1209                                     &maint_child_death, NULL);
1210
1211   if (GNUNET_OK !=
1212       GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "GLOBAL_PREFIX",
1213                                              &prefix_command))
1214     prefix_command = GNUNET_strdup ("");
1215   if (GNUNET_OK !=
1216       GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "GLOBAL_POSTFIX",
1217                                              &final_option))
1218     final_option = GNUNET_strdup ("");
1219
1220   GNUNET_CONFIGURATION_iterate_sections (cfg, &setup_service, NULL);
1221
1222   /* start default services... */
1223   if (GNUNET_OK ==
1224       GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "DEFAULTSERVICES",
1225                                              &defaultservices))
1226     {
1227       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1228                   _("Starting default services `%s'\n"), defaultservices);
1229       if (0 < strlen (defaultservices))
1230         {
1231           for (pos = strtok (defaultservices, " "); NULL != pos;
1232                pos = strtok (NULL, " "))
1233             {
1234               sl = find_service (pos);
1235               if (NULL == sl)
1236                 {
1237                   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1238                               _
1239                               ("Default service `%s' not configured correctly!\n"),
1240                               pos);
1241                   continue;
1242                 }
1243               sl->is_default = GNUNET_YES;
1244               start_process (sl);
1245             }
1246         }
1247       GNUNET_free (defaultservices);
1248     }
1249   else
1250     {
1251       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1252                   _
1253                   ("No default services configured, GNUnet will not really start right now.\n"));
1254     }
1255
1256   /* process client requests */
1257   GNUNET_SERVER_add_handlers (server, handlers);
1258 }
1259
1260
1261 /**
1262  * The main function for the arm service.
1263  *
1264  * @param argc number of arguments from the command line
1265  * @param argv command line arguments
1266  * @return 0 ok, 1 on error
1267  */
1268 int
1269 main (int argc, char *const *argv)
1270 {
1271   int ret;
1272   struct GNUNET_SIGNAL_Context *shc_chld;
1273
1274   sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
1275   GNUNET_assert (sigpipe != NULL);
1276   shc_chld =
1277     GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
1278   ret =
1279     (GNUNET_OK ==
1280      GNUNET_SERVICE_run (argc, argv, "arm", 
1281                          GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN, &run, NULL)) ? 0 : 1;
1282   GNUNET_SIGNAL_handler_uninstall (shc_chld);
1283   shc_chld = NULL;
1284   GNUNET_DISK_pipe_close (sigpipe);
1285   sigpipe = NULL;
1286   return ret;
1287 }
1288
1289
1290 #ifdef LINUX
1291 #include <malloc.h>
1292
1293 /**
1294  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1295  */
1296 void __attribute__ ((constructor)) GNUNET_ARM_memory_init ()
1297 {
1298   mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1299   mallopt (M_TOP_PAD, 1 * 1024);
1300   malloc_trim (0);
1301 }
1302 #endif
1303
1304
1305 /* end of gnunet-service-arm.c */