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