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