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