-options to play with
[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   if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
493     return;
494   start_process (sl);
495 }
496
497
498 /**
499  * Creating a listening socket for each of the service's addresses and
500  * wait for the first incoming connection to it
501  *
502  * @param sa address associated with the service
503  * @param addr_len length of sa
504  * @param sl service entry for the service in question
505  */
506 static void
507 create_listen_socket (struct sockaddr *sa, socklen_t addr_len,
508                       struct ServiceList *sl)
509 {
510   static int on = 1;
511   struct GNUNET_NETWORK_Handle *sock;
512   struct ServiceListeningInfo *sli;
513
514   switch (sa->sa_family)
515     {
516     case AF_INET:
517       sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
518       break;
519     case AF_INET6:
520       sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
521       break;
522     case AF_UNIX:
523       if (strcmp (GNUNET_a2s (sa, addr_len), "@") == 0) /* Do not bind to blank UNIX path! */
524         return;
525       sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
526       break;
527     default:
528       GNUNET_break (0);
529       sock = NULL;
530       errno = EAFNOSUPPORT;
531       break;
532     }
533   if (NULL == sock)
534     {
535       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
536                   _("Unable to create socket for service `%s': %s\n"),
537                   sl->name, STRERROR (errno));
538       GNUNET_free (sa);
539       return;
540     }
541   if (GNUNET_NETWORK_socket_setsockopt
542       (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
543     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
544                          "setsockopt");
545 #ifdef IPV6_V6ONLY
546   if ((sa->sa_family == AF_INET6) &&
547       (GNUNET_NETWORK_socket_setsockopt
548        (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK))
549     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
550                          "setsockopt");
551 #endif
552
553   if (GNUNET_NETWORK_socket_bind
554       (sock, (const struct sockaddr *) sa, addr_len) != GNUNET_OK)
555     {
556       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
557                   _
558                   ("Unable to bind listening socket for service `%s' to address `%s': %s\n"),
559                   sl->name, GNUNET_a2s (sa, addr_len), STRERROR (errno));
560       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
561       GNUNET_free (sa);
562       return;
563     }
564   if (GNUNET_NETWORK_socket_listen (sock, 5) != GNUNET_OK)
565     {
566       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
567       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
568       GNUNET_free (sa);
569       return;
570     }
571   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
572               _("ARM now monitors connections to service `%s' at `%s'\n"),
573               sl->name, GNUNET_a2s (sa, addr_len));
574   sli = GNUNET_malloc (sizeof (struct ServiceListeningInfo));
575   sli->service_addr = sa;
576   sli->service_addr_len = addr_len;
577   sli->listen_socket = sock;
578   sli->sl = sl;
579   sli->accept_task =
580     GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sock,
581                                    &accept_connection, sli);
582   GNUNET_CONTAINER_DLL_insert (sl->listen_head, sl->listen_tail, sli);
583 }
584
585
586 /**
587  * Remove and free an entry in the service list.  Listen sockets
588  * must have already been cleaned up.  Only to be called during shutdown.
589  *
590  * @param sl entry to free
591  */
592 static void
593 free_service (struct ServiceList *sl)
594 {
595   GNUNET_assert (GNUNET_YES == in_shutdown);
596   GNUNET_CONTAINER_DLL_remove (running_head, running_tail, sl);
597   GNUNET_assert (NULL == sl->listen_head);
598   GNUNET_free_non_null (sl->config);
599   GNUNET_free_non_null (sl->binary);
600   GNUNET_free (sl->name);
601   GNUNET_free (sl);
602 }
603
604
605 /**
606  * Handle START-message.
607  *
608  * @param cls closure (always NULL)
609  * @param client identification of the client
610  * @param message the actual message
611  * @return GNUNET_OK to keep the connection open,
612  *         GNUNET_SYSERR to close it (signal serious error)
613  */
614 static void
615 handle_start (void *cls, struct GNUNET_SERVER_Client *client,
616               const struct GNUNET_MessageHeader *message)
617 {
618   const char *servicename;
619   struct ServiceList *sl;
620   uint16_t size;
621   
622   size = ntohs (message->size);
623   size -= sizeof (struct GNUNET_MessageHeader);
624   servicename = (const char *) &message[1];
625   if ((size == 0) || (servicename[size - 1] != '\0'))
626     {
627       GNUNET_break (0);
628       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
629       return;
630     }
631   if (GNUNET_YES == in_shutdown)
632     {
633       signal_result (client, servicename, GNUNET_ARM_PROCESS_SHUTDOWN);
634       return;
635     }
636   sl = find_service (servicename);
637   if (NULL == sl)
638     {
639       signal_result (client, servicename, GNUNET_ARM_PROCESS_UNKNOWN);
640       return;
641     }
642   sl->is_default = GNUNET_YES;
643   if (sl->proc != NULL)
644     {
645       signal_result (client, servicename, GNUNET_ARM_PROCESS_ALREADY_RUNNING);
646       return;
647     }
648   start_process (sl);
649   signal_result (client, servicename, GNUNET_ARM_PROCESS_STARTING);
650 }
651
652
653 /**
654  * Handle STOP-message.
655  *
656  * @param cls closure (always NULL)
657  * @param client identification of the client
658  * @param message the actual message
659  * @return GNUNET_OK to keep the connection open,
660  *         GNUNET_SYSERR to close it (signal serious error)
661  */
662 static void
663 handle_stop (void *cls, struct GNUNET_SERVER_Client *client,
664              const struct GNUNET_MessageHeader *message)
665 {
666   struct ServiceList *sl;
667   const char *servicename;
668   uint16_t size;
669
670   size = ntohs (message->size);
671   size -= sizeof (struct GNUNET_MessageHeader);
672   servicename = (const char *) &message[1];
673   if ((size == 0) || (servicename[size - 1] != '\0'))
674     {
675       GNUNET_break (0);
676       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
677       return;
678     }
679   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
680               _("Preparing to stop `%s'\n"), servicename);
681   sl = find_service (servicename);
682   if (sl == NULL)
683     {
684       signal_result (client, servicename, GNUNET_ARM_PROCESS_UNKNOWN);
685       return;
686     }
687   sl->is_default = GNUNET_NO;
688   if (GNUNET_YES == in_shutdown)
689     {
690       /* shutdown in progress */
691       signal_result (client, servicename, GNUNET_ARM_PROCESS_SHUTDOWN);
692       return;
693     }
694   if (sl->killing_client != NULL)
695     {
696       /* killing already in progress */
697       signal_result (client, servicename,
698                      GNUNET_ARM_PROCESS_ALREADY_STOPPING);
699       return;
700     }
701   if (sl->proc == NULL)
702     {
703       /* process is down */
704       signal_result (client, servicename, GNUNET_ARM_PROCESS_ALREADY_DOWN);
705       return;
706     }
707   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
708               "Sending kill signal to service `%s', waiting for process to die.\n",
709               servicename);
710   sl->killed_at = GNUNET_TIME_absolute_get ();
711   if (0 != GNUNET_OS_process_kill (sl->proc, SIGTERM))
712     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
713   sl->killing_client = client;
714   GNUNET_SERVER_client_keep (client);
715 }
716
717 /**
718  * Handle LIST-message.
719  *
720  * @param cls closure (always NULL)
721  * @param client identification of the client
722  * @param message the actual message
723  */
724 static void
725 handle_list (void *cls, struct GNUNET_SERVER_Client *client,
726              const struct GNUNET_MessageHeader *message)
727 {
728   struct GNUNET_ARM_ListResultMessage *msg;
729   size_t string_list_size;
730   size_t total_size;
731   struct ServiceList *sl;
732   uint16_t count;
733   
734   if (NULL == client)
735     return;
736   
737   count = 0;
738   string_list_size = 0;
739   /* first count the running processes get their name's size */
740   for (sl = running_head; sl != NULL; sl = sl->next)
741   {
742     if (sl->proc != NULL)
743     {
744       string_list_size += strlen (sl->name);
745       string_list_size += strlen (sl->binary);
746       string_list_size += 4;
747       count++;
748     }
749   }
750   total_size = sizeof (struct GNUNET_ARM_ListResultMessage) 
751                + string_list_size;
752   msg = GNUNET_malloc (total_size);
753   msg->header.size = total_size;
754   msg->header.type = GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT;
755   msg->count = count;
756   
757   char *pos = (char *)&msg[1];
758   for (sl = running_head; sl != NULL; sl = sl->next) 
759   {
760     if (sl->proc != NULL)
761     {
762       size_t s = strlen (sl->name) + strlen (sl->binary) + 4;
763       GNUNET_snprintf(pos, s, "%s (%s)", sl->name, sl->binary);
764       pos += s;
765     }
766   }
767   
768   GNUNET_SERVER_notify_transmit_ready (client,
769                                        msg->header.size,
770                                        GNUNET_TIME_UNIT_FOREVER_REL,
771                                        &write_list_result, msg);
772   GNUNET_SERVER_receive_done (client, GNUNET_OK);
773 }
774
775 /**
776  * We are done with everything.  Stop remaining
777  * tasks, signal handler and the server.
778  */
779 static void
780 do_shutdown ()
781 {
782   if (NULL != server)
783     {
784       GNUNET_SERVER_destroy (server);
785       server = NULL;
786     }
787   if (GNUNET_SCHEDULER_NO_TASK != child_death_task)
788     {
789       GNUNET_SCHEDULER_cancel (child_death_task);
790       child_death_task = GNUNET_SCHEDULER_NO_TASK;
791     }
792 }
793
794
795 /**
796  * Task run for shutdown.
797  *
798  * @param cls closure, NULL if we need to self-restart
799  * @param tc context
800  */
801 static void
802 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
803 {
804   struct ServiceList *pos;
805   struct ServiceList *nxt;
806   struct ServiceListeningInfo *sli;
807
808   if (GNUNET_SCHEDULER_NO_TASK != child_restart_task)
809   {
810     GNUNET_SCHEDULER_cancel (child_restart_task);
811     child_restart_task = GNUNET_SCHEDULER_NO_TASK;
812   }
813   in_shutdown = GNUNET_YES;
814   /* first, stop listening */
815   for (pos = running_head; NULL != pos; pos = pos->next)
816   {
817     while (NULL != (sli = pos->listen_head))
818       {
819         GNUNET_CONTAINER_DLL_remove (pos->listen_head,
820                                      pos->listen_tail, sli);
821         if (sli->accept_task != GNUNET_SCHEDULER_NO_TASK)
822           {
823             GNUNET_SCHEDULER_cancel (sli->accept_task);
824             sli->accept_task = GNUNET_SCHEDULER_NO_TASK;
825           }
826         GNUNET_break (GNUNET_OK ==
827                       GNUNET_NETWORK_socket_close (sli->listen_socket));
828         GNUNET_free (sli->service_addr);
829         GNUNET_free (sli);
830       }
831   }
832   /* then, shutdown all existing service processes */
833   nxt = running_head;
834   while (NULL != (pos = nxt))
835   {
836     nxt = pos->next;
837     if (pos->proc != NULL)
838     {
839       GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping service `%s'\n",
840                   pos->name);
841       pos->killed_at = GNUNET_TIME_absolute_get ();
842       if (0 != GNUNET_OS_process_kill (pos->proc, SIGTERM))
843         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
844     }
845     else
846     {
847       free_service (pos);
848     }
849   }
850   /* finally, should all service processes be already gone, terminate for real */
851   if (running_head == NULL)
852     do_shutdown ();
853 }
854
855
856 /**
857  * Task run whenever it is time to restart a child that died.
858  *
859  * @param cls closure, always NULL
860  * @param tc context
861  */
862 static void
863 delayed_restart_task (void *cls,
864                       const struct GNUNET_SCHEDULER_TaskContext *tc)
865 {
866   struct ServiceList *sl;
867   struct GNUNET_TIME_Relative lowestRestartDelay;
868   struct ServiceListeningInfo *sli;
869
870   child_restart_task = GNUNET_SCHEDULER_NO_TASK;
871   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
872     return;
873   GNUNET_assert (GNUNET_NO == in_shutdown);
874   lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL;
875
876   /* check for services that need to be restarted due to
877    * configuration changes or because the last restart failed */
878   for (sl = running_head; NULL != sl; sl = sl->next)
879   {
880     if (NULL != sl->proc)
881       continue;
882     /* service is currently not running */
883     if (GNUNET_TIME_absolute_get_remaining (sl->restart_at).rel_value ==
884         0)
885     {
886       /* restart is now allowed */
887       if (sl->is_default)
888       {
889         /* process should run by default, start immediately */
890         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
891                     _("Restarting service `%s'.\n"), sl->name);
892         start_process (sl);
893       }
894       else
895       {
896         /* process is run on-demand, ensure it is re-started if there is demand */
897         for (sli = sl->listen_head; NULL != sli; sli = sli->next)
898           if (GNUNET_SCHEDULER_NO_TASK == sli->accept_task)
899           {
900             /* accept was actually paused, so start it again */
901             sli->accept_task =
902               GNUNET_SCHEDULER_add_read_net
903               (GNUNET_TIME_UNIT_FOREVER_REL, sli->listen_socket,
904                &accept_connection, sli);
905           }
906       }
907     }
908     else
909     {
910       /* update calculation for earliest time to reactivate a service */
911       lowestRestartDelay =
912         GNUNET_TIME_relative_min (lowestRestartDelay,
913                                   GNUNET_TIME_absolute_get_remaining
914                                   (sl->restart_at));
915     }
916   }
917   if (lowestRestartDelay.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
918   {
919     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
920                 "Will restart process in %s\n",
921                 GNUNET_STRINGS_relative_time_to_string (lowestRestartDelay, GNUNET_YES));
922     child_restart_task =
923       GNUNET_SCHEDULER_add_delayed_with_priority (lowestRestartDelay,
924                                                   GNUNET_SCHEDULER_PRIORITY_IDLE, 
925                                                   &delayed_restart_task, NULL);
926   }
927 }
928
929
930 /**
931  * Task triggered whenever we receive a SIGCHLD (child
932  * process died).
933  *
934  * @param cls closure, NULL if we need to self-restart
935  * @param tc context
936  */
937 static void
938 maint_child_death (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
939 {
940   struct ServiceList *pos;
941   struct ServiceList *next;
942   struct ServiceListeningInfo *sli;
943   const char *statstr;
944   int statcode;
945   int ret;
946   char c[16];
947   enum GNUNET_OS_ProcessStatusType statusType;
948   unsigned long statusCode;
949   const struct GNUNET_DISK_FileHandle *pr;
950
951   pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
952   child_death_task = GNUNET_SCHEDULER_NO_TASK;
953   if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
954     {
955       /* shutdown scheduled us, ignore! */
956       child_death_task =
957         GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
958                                         pr, &maint_child_death, NULL);
959       return;
960     }
961   /* consume the signal */
962   GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
963
964   /* check for services that died (WAITPID) */
965   next = running_head;
966   while (NULL != (pos = next))
967     {
968       next = pos->next;
969
970       if (pos->proc == NULL)
971       {
972         if (GNUNET_YES == in_shutdown)
973           free_service (pos);
974         continue;
975       }
976       if ((GNUNET_SYSERR ==
977            (ret =
978             GNUNET_OS_process_status (pos->proc, &statusType, &statusCode)))
979           || ((ret == GNUNET_NO) || (statusType == GNUNET_OS_PROCESS_STOPPED)
980               || (statusType == GNUNET_OS_PROCESS_RUNNING)))
981         continue;
982       if (statusType == GNUNET_OS_PROCESS_EXITED)
983       {
984         statstr = _( /* process termination method */ "exit");
985         statcode = statusCode;
986       }
987       else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
988       {
989         statstr = _( /* process termination method */ "signal");
990         statcode = statusCode;
991       }
992       else
993       {
994         statstr = _( /* process termination method */ "unknown");
995         statcode = 0;
996       }
997       if (0 != pos->killed_at.abs_value)
998       {
999         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1000                     _("Service `%s' took %s to terminate\n"),
1001                     pos->name,
1002                     GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->killed_at), GNUNET_YES));
1003       }
1004       GNUNET_OS_process_destroy (pos->proc);
1005       pos->proc = NULL;
1006       if (NULL != pos->killing_client)
1007         {
1008           signal_result (pos->killing_client, pos->name,
1009                          GNUNET_ARM_PROCESS_DOWN);
1010           GNUNET_SERVER_client_drop (pos->killing_client);
1011           pos->killing_client = NULL;
1012           /* process can still be re-started on-demand, ensure it is re-started if there is demand */
1013           for (sli = pos->listen_head; NULL != sli; sli = sli->next)
1014             {
1015               GNUNET_break (GNUNET_SCHEDULER_NO_TASK == sli->accept_task);
1016               sli->accept_task =
1017                 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1018                                                sli->listen_socket,
1019                                                &accept_connection, sli);
1020             }
1021           continue;
1022         }
1023       if (GNUNET_YES != in_shutdown)
1024         {
1025           if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0))
1026             {
1027               /* process terminated normally, allow restart at any time */
1028               pos->restart_at.abs_value = 0;
1029             }
1030           else
1031             {
1032               if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1033                 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1034                             _
1035                             ("Service `%s' terminated with status %s/%d, will restart in %llu ms\n"),
1036                             pos->name, statstr, statcode, pos->backoff.rel_value);
1037               /* schedule restart */
1038               pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff);
1039               pos->backoff = GNUNET_TIME_STD_BACKOFF (pos->backoff);
1040             }
1041           if (GNUNET_SCHEDULER_NO_TASK != child_restart_task)
1042             GNUNET_SCHEDULER_cancel (child_restart_task);
1043           child_restart_task =
1044             GNUNET_SCHEDULER_add_with_priority
1045             (GNUNET_SCHEDULER_PRIORITY_IDLE, 
1046              &delayed_restart_task, NULL);
1047         }
1048       else
1049         {
1050           free_service (pos);
1051         }
1052     }
1053   child_death_task =
1054     GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1055                                     pr, &maint_child_death, NULL);
1056   if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
1057     do_shutdown ();
1058 }
1059
1060
1061 /**
1062  * Handler for SHUTDOWN message.
1063  *
1064  * @param cls closure (refers to service)
1065  * @param client identification of the client
1066  * @param message the actual message
1067  */
1068 static void
1069 handle_shutdown (void *cls, struct GNUNET_SERVER_Client *client,
1070                  const struct GNUNET_MessageHeader *message)
1071 {
1072   GNUNET_SCHEDULER_shutdown ();
1073   GNUNET_SERVER_client_persist_ (client);
1074 }
1075
1076
1077 /**
1078  * Signal handler called for SIGCHLD.  Triggers the
1079  * respective handler by writing to the trigger pipe.
1080  */
1081 static void
1082 sighandler_child_death ()
1083 {
1084   static char c;
1085   int old_errno = errno;        /* back-up errno */
1086
1087   GNUNET_break (1 ==
1088                 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
1089                                         (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
1090                                         &c, sizeof (c)));
1091   errno = old_errno;            /* restore errno */
1092 }
1093
1094
1095 /**
1096  * Setup our service record for the given section in the configuration file
1097  * (assuming the section is for a service).
1098  *
1099  * @param cls unused
1100  * @param section a section in the configuration file
1101  * @return GNUNET_OK (continue)
1102  */
1103 static void
1104 setup_service (void *cls, const char *section)
1105 {
1106   struct ServiceList *sl;
1107   char *binary;
1108   char *config;
1109   struct stat sbuf;
1110   struct sockaddr **addrs;
1111   socklen_t *addr_lens;
1112   int ret;
1113   unsigned int i;
1114
1115   if (strcasecmp (section, "arm") == 0)
1116     return;
1117   if (GNUNET_OK !=
1118       GNUNET_CONFIGURATION_get_value_string (cfg, section, "BINARY", &binary))
1119     {
1120       /* not a service section */
1121       return;
1122     }
1123   sl = find_service (section);
1124   if (NULL != sl)
1125   {
1126     /* got the same section twice!? */
1127     GNUNET_break (0);
1128     return;
1129   }
1130   config = NULL;
1131   if (( (GNUNET_OK !=
1132          GNUNET_CONFIGURATION_get_value_filename (cfg, section, "CONFIG",
1133                                                   &config)) &&
1134         (GNUNET_OK !=
1135          GNUNET_CONFIGURATION_get_value_filename (cfg, "PATHS", "DEFAULTCONFIG",
1136                                                   &config)) ) ||
1137       (0 != STAT (config, &sbuf)))
1138   {
1139     if (NULL != config)
1140     {
1141       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, 
1142                                  section, "CONFIG",
1143                                  STRERROR (errno));
1144       GNUNET_free (config);
1145       config = NULL;
1146     }
1147   }
1148   sl = GNUNET_malloc (sizeof (struct ServiceList));
1149   sl->name = GNUNET_strdup (section);
1150   sl->binary = binary;
1151   sl->config = config;
1152   sl->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
1153   sl->restart_at = GNUNET_TIME_UNIT_FOREVER_ABS;
1154 #if WINDOWS
1155   sl->pipe_control = GNUNET_YES;
1156 #else
1157   if (GNUNET_CONFIGURATION_have_value (cfg, section, "PIPECONTROL"))
1158     sl->pipe_control = GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "PIPECONTROL");
1159 #endif  
1160   GNUNET_CONTAINER_DLL_insert (running_head, running_tail, sl);
1161   if (GNUNET_YES !=
1162       GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "AUTOSTART"))
1163     return;
1164   if (0 >= (ret = GNUNET_SERVICE_get_server_addresses (section, cfg,
1165                                                        &addrs, &addr_lens)))
1166     return;
1167   /* this will free (or capture) addrs[i] */
1168   for (i = 0; i < ret; i++)
1169     create_listen_socket (addrs[i], addr_lens[i], sl);
1170   GNUNET_free (addrs);
1171   GNUNET_free (addr_lens);
1172 }
1173
1174
1175 /**
1176  * Process arm requests.
1177  *
1178  * @param cls closure
1179  * @param serv the initialized server
1180  * @param c configuration to use
1181  */
1182 static void
1183 run (void *cls, struct GNUNET_SERVER_Handle *serv,
1184      const struct GNUNET_CONFIGURATION_Handle *c)
1185 {
1186   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1187     {&handle_start, NULL, GNUNET_MESSAGE_TYPE_ARM_START, 0},
1188     {&handle_stop, NULL, GNUNET_MESSAGE_TYPE_ARM_STOP, 0},
1189     {&handle_shutdown, NULL, GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN,
1190      sizeof (struct GNUNET_MessageHeader)},
1191     {&handle_list, NULL, GNUNET_MESSAGE_TYPE_ARM_LIST, 
1192      sizeof (struct GNUNET_MessageHeader)},
1193     {NULL, NULL, 0, 0}
1194   };
1195   char *defaultservices;
1196   const char *pos;
1197   struct ServiceList *sl;
1198
1199   cfg = c;
1200   server = serv;
1201   GNUNET_assert (serv != NULL);
1202   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1203                                 NULL);
1204   child_death_task =
1205     GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1206                                     GNUNET_DISK_pipe_handle (sigpipe,
1207                                                              GNUNET_DISK_PIPE_END_READ),
1208                                     &maint_child_death, NULL);
1209
1210   if (GNUNET_OK !=
1211       GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "GLOBAL_PREFIX",
1212                                              &prefix_command))
1213     prefix_command = GNUNET_strdup ("");
1214   if (GNUNET_OK !=
1215       GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "GLOBAL_POSTFIX",
1216                                              &final_option))
1217     final_option = GNUNET_strdup ("");
1218
1219   GNUNET_CONFIGURATION_iterate_sections (cfg, &setup_service, NULL);
1220
1221   /* start default services... */
1222   if (GNUNET_OK ==
1223       GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "DEFAULTSERVICES",
1224                                              &defaultservices))
1225     {
1226       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1227                   _("Starting default services `%s'\n"), defaultservices);
1228       if (0 < strlen (defaultservices))
1229         {
1230           for (pos = strtok (defaultservices, " "); NULL != pos;
1231                pos = strtok (NULL, " "))
1232             {
1233               sl = find_service (pos);
1234               if (NULL == sl)
1235                 {
1236                   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1237                               _
1238                               ("Default service `%s' not configured correctly!\n"),
1239                               pos);
1240                   continue;
1241                 }
1242               sl->is_default = GNUNET_YES;
1243               start_process (sl);
1244             }
1245         }
1246       GNUNET_free (defaultservices);
1247     }
1248   else
1249     {
1250       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1251                   _
1252                   ("No default services configured, GNUnet will not really start right now.\n"));
1253     }
1254
1255   /* process client requests */
1256   GNUNET_SERVER_add_handlers (server, handlers);
1257 }
1258
1259
1260 /**
1261  * The main function for the arm service.
1262  *
1263  * @param argc number of arguments from the command line
1264  * @param argv command line arguments
1265  * @return 0 ok, 1 on error
1266  */
1267 int
1268 main (int argc, char *const *argv)
1269 {
1270   int ret;
1271   struct GNUNET_SIGNAL_Context *shc_chld;
1272
1273   sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
1274   GNUNET_assert (sigpipe != NULL);
1275   shc_chld =
1276     GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
1277   ret =
1278     (GNUNET_OK ==
1279      GNUNET_SERVICE_run (argc, argv, "arm", 
1280                          GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN, &run, NULL)) ? 0 : 1;
1281   GNUNET_SIGNAL_handler_uninstall (shc_chld);
1282   shc_chld = NULL;
1283   GNUNET_DISK_pipe_close (sigpipe);
1284   sigpipe = NULL;
1285   return ret;
1286 }
1287
1288
1289 #ifdef LINUX
1290 #include <malloc.h>
1291
1292 /**
1293  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1294  */
1295 void __attribute__ ((constructor)) GNUNET_ARM_memory_init ()
1296 {
1297   mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1298   mallopt (M_TOP_PAD, 1 * 1024);
1299   malloc_trim (0);
1300 }
1301 #endif
1302
1303
1304 /* end of gnunet-service-arm.c */