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