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