added ATS addresstype information to unix
[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 (lowestRestartDelay,
809                                       &delayed_restart_task, NULL);
810     }
811 }
812
813
814 /**
815  * Task triggered whenever we receive a SIGCHLD (child
816  * process died).
817  *
818  * @param cls closure, NULL if we need to self-restart
819  * @param tc context
820  */
821 static void
822 maint_child_death (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
823 {
824   struct ServiceList *pos;
825   struct ServiceList *next;
826   struct ServiceListeningInfo *sli;
827   const char *statstr;
828   int statcode;
829   int ret;
830   char c[16];
831   enum GNUNET_OS_ProcessStatusType statusType;
832   unsigned long statusCode;
833   const struct GNUNET_DISK_FileHandle *pr;
834
835   pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
836   child_death_task = GNUNET_SCHEDULER_NO_TASK;
837   if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
838     {
839       /* shutdown scheduled us, ignore! */
840       child_death_task =
841         GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
842                                         pr, &maint_child_death, NULL);
843       return;
844     }
845   /* consume the signal */
846   GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
847
848   /* check for services that died (WAITPID) */
849   next = running_head;
850   while (NULL != (pos = next))
851     {
852       next = pos->next;
853
854       if (pos->proc == NULL)
855         {
856           if (GNUNET_YES == in_shutdown)
857             free_service (pos);
858           continue;
859         }
860       if ((GNUNET_SYSERR ==
861            (ret =
862             GNUNET_OS_process_status (pos->proc, &statusType, &statusCode)))
863           || ((ret == GNUNET_NO) || (statusType == GNUNET_OS_PROCESS_STOPPED)
864               || (statusType == GNUNET_OS_PROCESS_RUNNING)))
865         continue;
866       if (statusType == GNUNET_OS_PROCESS_EXITED)
867         {
868           statstr = _( /* process termination method */ "exit");
869           statcode = statusCode;
870         }
871       else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
872         {
873           statstr = _( /* process termination method */ "signal");
874           statcode = statusCode;
875         }
876       else
877         {
878           statstr = _( /* process termination method */ "unknown");
879           statcode = 0;
880         }
881       GNUNET_OS_process_close (pos->proc);
882       pos->proc = NULL;
883       if (NULL != pos->killing_client)
884         {
885           signal_result (pos->killing_client, pos->name,
886                          GNUNET_ARM_PROCESS_DOWN);
887           GNUNET_SERVER_client_drop (pos->killing_client);
888           pos->killing_client = NULL;
889           /* process can still be re-started on-demand, ensure it is re-started if there is demand */
890           for (sli = pos->listen_head; NULL != sli; sli = sli->next)
891             {
892               GNUNET_break (GNUNET_SCHEDULER_NO_TASK == sli->accept_task);
893               sli->accept_task =
894                 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
895                                                sli->listen_socket,
896                                                &accept_connection, sli);
897             }
898           continue;
899         }
900       if (GNUNET_YES != in_shutdown)
901         {
902           if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0))
903             {
904               /* process terminated normally, allow restart at any time */
905               pos->restart_at.abs_value = 0;
906               continue;
907             }
908           if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
909             GNUNET_log (GNUNET_ERROR_TYPE_INFO,
910                         _
911                         ("Service `%s' terminated with status %s/%d, will restart in %llu ms\n"),
912                         pos->name, statstr, statcode, pos->backoff.rel_value);
913           /* schedule restart */
914           pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff);
915           pos->backoff =
916             GNUNET_TIME_relative_min (EXPONENTIAL_BACKOFF_THRESHOLD,
917                                       GNUNET_TIME_relative_multiply
918                                       (pos->backoff, 2));
919           if (GNUNET_SCHEDULER_NO_TASK != child_restart_task)
920             GNUNET_SCHEDULER_cancel (child_restart_task);
921           child_restart_task =
922             GNUNET_SCHEDULER_add_with_priority
923             (GNUNET_SCHEDULER_PRIORITY_IDLE, &delayed_restart_task, NULL);
924         }
925       else
926         {
927           free_service (pos);
928         }
929     }
930   child_death_task =
931     GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
932                                     pr, &maint_child_death, NULL);
933   if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
934     do_shutdown ();
935 }
936
937
938 /**
939  * Transmit our shutdown acknowledgement to the client.
940  *
941  * @param cls the 'struct GNUNET_SERVER_Client'
942  * @param size number of bytes available in buf
943  * @param buf where to write the message
944  * @return number of bytes written
945  */
946 static size_t
947 transmit_shutdown_ack (void *cls, size_t size, void *buf)
948 {
949   struct GNUNET_SERVER_Client *client = cls;
950   struct GNUNET_ARM_ResultMessage *msg;
951
952   if (size < sizeof (struct GNUNET_ARM_ResultMessage))
953     {
954       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
955                   _("Failed to transmit shutdown ACK.\n"));
956       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
957       return 0;                 /* client disconnected */
958     }
959   /* Make the connection flushing for the purpose of ACK transmitting,
960    * needed on W32 to ensure that the message is even received, harmless
961    * on other platforms... */
962   GNUNET_break (GNUNET_OK == GNUNET_SERVER_client_disable_corking (client));
963   msg = (struct GNUNET_ARM_ResultMessage *) buf;
964   msg->header.type = htons (GNUNET_MESSAGE_TYPE_ARM_RESULT);
965   msg->header.size = htons (sizeof (struct GNUNET_ARM_ResultMessage));
966   msg->status = htonl ((uint32_t) GNUNET_ARM_PROCESS_SHUTDOWN);
967   GNUNET_SERVER_receive_done (client, GNUNET_OK);
968   GNUNET_SERVER_client_drop (client);
969   return sizeof (struct GNUNET_ARM_ResultMessage);
970 }
971
972
973 /**
974  * Handler for SHUTDOWN message.
975  *
976  * @param cls closure (refers to service)
977  * @param client identification of the client
978  * @param message the actual message
979  */
980 static void
981 handle_shutdown (void *cls, struct GNUNET_SERVER_Client *client,
982                  const struct GNUNET_MessageHeader *message)
983 {
984   GNUNET_SCHEDULER_shutdown ();
985   GNUNET_SERVER_client_keep (client);
986   GNUNET_SERVER_notify_transmit_ready (client,
987                                        sizeof (struct GNUNET_ARM_ResultMessage),
988                                        GNUNET_TIME_UNIT_FOREVER_REL,
989                                        &transmit_shutdown_ack, client);
990   GNUNET_SERVER_client_persist_ (client);
991 }
992
993
994 /**
995  * Signal handler called for SIGCHLD.  Triggers the
996  * respective handler by writing to the trigger pipe.
997  */
998 static void
999 sighandler_child_death ()
1000 {
1001   static char c;
1002   int old_errno = errno;        /* back-up errno */
1003
1004   GNUNET_break (1 ==
1005                 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
1006                                         (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
1007                                         &c, sizeof (c)));
1008   errno = old_errno;            /* restore errno */
1009 }
1010
1011
1012 /**
1013  * Setup our service record for the given section in the configuration file
1014  * (assuming the section is for a service).
1015  *
1016  * @param cls unused
1017  * @param section a section in the configuration file
1018  * @return GNUNET_OK (continue)
1019  */
1020 static void
1021 setup_service (void *cls, const char *section)
1022 {
1023   struct ServiceList *sl;
1024   char *binary;
1025   char *config;
1026   struct stat sbuf;
1027   struct sockaddr **addrs;
1028   socklen_t *addr_lens;
1029   int ret;
1030   unsigned int i;
1031
1032   if (strcasecmp (section, "arm") == 0)
1033     return;
1034   if (GNUNET_OK !=
1035       GNUNET_CONFIGURATION_get_value_string (cfg, section, "BINARY", &binary))
1036     {
1037       /* not a service section */
1038       return;
1039     }
1040   config = NULL;
1041   if ((GNUNET_OK !=
1042        GNUNET_CONFIGURATION_get_value_filename (cfg, section, "CONFIG",
1043                                                 &config)) ||
1044       (0 != STAT (config, &sbuf)))
1045     {
1046       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1047                   _
1048                   ("Configuration file `%s' for service `%s' not valid: %s\n"),
1049                   config, section,
1050                   (config == NULL) ? _("option missing") : STRERROR (errno));
1051       GNUNET_free (binary);
1052       GNUNET_free_non_null (config);
1053       return;
1054     }
1055   sl = GNUNET_malloc (sizeof (struct ServiceList));
1056   sl->name = GNUNET_strdup (section);
1057   sl->binary = binary;
1058   sl->config = config;
1059   sl->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
1060   sl->restart_at = GNUNET_TIME_UNIT_FOREVER_ABS;
1061   GNUNET_CONTAINER_DLL_insert (running_head, running_tail, sl);
1062   if (GNUNET_YES !=
1063       GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "AUTOSTART"))
1064     return;
1065   if (0 >= (ret = GNUNET_SERVICE_get_server_addresses (section, cfg,
1066                                                        &addrs, &addr_lens)))
1067     return;
1068   /* this will free (or capture) addrs[i] */
1069   for (i = 0; i < ret; i++)
1070     create_listen_socket (addrs[i], addr_lens[i], sl);
1071   GNUNET_free (addrs);
1072   GNUNET_free (addr_lens);
1073 }
1074
1075
1076 /**
1077  * Process arm requests.
1078  *
1079  * @param cls closure
1080  * @param serv the initialized server
1081  * @param c configuration to use
1082  */
1083 static void
1084 run (void *cls, struct GNUNET_SERVER_Handle *serv,
1085      const struct GNUNET_CONFIGURATION_Handle *c)
1086 {
1087   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1088     {&handle_start, NULL, GNUNET_MESSAGE_TYPE_ARM_START, 0},
1089     {&handle_stop, NULL, GNUNET_MESSAGE_TYPE_ARM_STOP, 0},
1090     {&handle_shutdown, NULL, GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN,
1091      sizeof (struct GNUNET_MessageHeader)},
1092     {NULL, NULL, 0, 0}
1093   };
1094   char *defaultservices;
1095   const char *pos;
1096   struct ServiceList *sl;
1097
1098   cfg = c;
1099   server = serv;
1100   GNUNET_assert (serv != NULL);
1101   GNUNET_SERVER_ignore_shutdown (serv, GNUNET_YES);
1102   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1103                                 NULL);
1104   child_death_task =
1105     GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1106                                     GNUNET_DISK_pipe_handle (sigpipe,
1107                                                              GNUNET_DISK_PIPE_END_READ),
1108                                     &maint_child_death, NULL);
1109
1110   if (GNUNET_OK !=
1111       GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "GLOBAL_PREFIX",
1112                                              &prefix_command))
1113     prefix_command = GNUNET_strdup ("");
1114   if (GNUNET_OK !=
1115       GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "GLOBAL_POSTFIX",
1116                                              &final_option))
1117     final_option = GNUNET_strdup ("");
1118
1119   GNUNET_CONFIGURATION_iterate_sections (cfg, &setup_service, NULL);
1120
1121   /* start default services... */
1122   if (GNUNET_OK ==
1123       GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "DEFAULTSERVICES",
1124                                              &defaultservices))
1125     {
1126       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1127                   _("Starting default services `%s'\n"), defaultservices);
1128       if (0 < strlen (defaultservices))
1129         {
1130           for (pos = strtok (defaultservices, " "); NULL != pos;
1131                pos = strtok (NULL, " "))
1132             {
1133               sl = find_service (pos);
1134               if (NULL == sl)
1135                 {
1136                   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1137                               _
1138                               ("Default service `%s' not configured correctly!\n"),
1139                               pos);
1140                   continue;
1141                 }
1142               sl->is_default = GNUNET_YES;
1143               start_process (sl);
1144             }
1145         }
1146       GNUNET_free (defaultservices);
1147     }
1148   else
1149     {
1150       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1151                   _
1152                   ("No default services configured, GNUnet will not really start right now.\n"));
1153     }
1154
1155   /* process client requests */
1156   GNUNET_SERVER_add_handlers (server, handlers);
1157 }
1158
1159
1160 /**
1161  * The main function for the arm service.
1162  *
1163  * @param argc number of arguments from the command line
1164  * @param argv command line arguments
1165  * @return 0 ok, 1 on error
1166  */
1167 int
1168 main (int argc, char *const *argv)
1169 {
1170   int ret;
1171   struct GNUNET_SIGNAL_Context *shc_chld;
1172
1173   sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO);
1174   GNUNET_assert (sigpipe != NULL);
1175   shc_chld =
1176     GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
1177   ret =
1178     (GNUNET_OK ==
1179      GNUNET_SERVICE_run (argc, argv, "arm", GNUNET_YES, &run, NULL)) ? 0 : 1;
1180   GNUNET_SIGNAL_handler_uninstall (shc_chld);
1181   shc_chld = NULL;
1182   GNUNET_DISK_pipe_close (sigpipe);
1183   sigpipe = NULL;
1184   return ret;
1185 }
1186
1187
1188 #ifdef LINUX
1189 #include <malloc.h>
1190
1191 /**
1192  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1193  */
1194 void __attribute__ ((constructor)) GNUNET_ARM_memory_init ()
1195 {
1196   mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1197   mallopt (M_TOP_PAD, 1 * 1024);
1198   malloc_trim (0);
1199 }
1200 #endif
1201
1202
1203 /* end of gnunet-service-arm.c */