use c99
[oweals/gnunet.git] / src / arm / gnunet-service-arm.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2010, 2011, 2015 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, 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 #if HAVE_WAIT4
33 /**
34  * Name of the file for writing resource utilization summaries to.
35  */
36 static char *wait_filename;
37
38 /**
39  * Handle for the file for writing resource summaries.
40  */
41 static FILE *wait_file;
42 #endif
43
44
45 /**
46  * How many messages do we queue up at most for optional
47  * notifications to a client?  (this can cause notifications
48  * about outgoing messages to be dropped).
49  */
50 #define MAX_NOTIFY_QUEUE 1024
51
52
53 /**
54  * List of our services.
55  */
56 struct ServiceList;
57
58
59 /**
60  * Record with information about a listen socket we have open.
61  */
62 struct ServiceListeningInfo
63 {
64   /**
65    * This is a linked list.
66    */
67   struct ServiceListeningInfo *next;
68
69   /**
70    * This is a linked list.
71    */
72   struct ServiceListeningInfo *prev;
73
74   /**
75    * Address this socket is listening on.
76    */
77   struct sockaddr *service_addr;
78
79   /**
80    * Service this listen socket is for.
81    */
82   struct ServiceList *sl;
83
84   /**
85    * Number of bytes in 'service_addr'
86    */
87   socklen_t service_addr_len;
88
89   /**
90    * Our listening socket.
91    */
92   struct GNUNET_NETWORK_Handle *listen_socket;
93
94   /**
95    * Task doing the accepting.
96    */
97   struct GNUNET_SCHEDULER_Task *accept_task;
98
99 };
100
101
102 /**
103  * List of our services.
104  */
105 struct ServiceList
106 {
107   /**
108    * This is a doubly-linked list.
109    */
110   struct ServiceList *next;
111
112   /**
113    * This is a doubly-linked list.
114    */
115   struct ServiceList *prev;
116
117   /**
118    * Linked list of listen sockets associated with this service.
119    */
120   struct ServiceListeningInfo *listen_head;
121
122   /**
123    * Linked list of listen sockets associated with this service.
124    */
125   struct ServiceListeningInfo *listen_tail;
126
127   /**
128    * Name of the service.
129    */
130   char *name;
131
132   /**
133    * Name of the binary used.
134    */
135   char *binary;
136
137   /**
138    * Name of the configuration file used.
139    */
140   char *config;
141
142   /**
143    * Client to notify upon kill completion (waitpid), NULL
144    * if we should simply restart the process.
145    */
146   struct GNUNET_SERVER_Client *killing_client;
147
148   /**
149    * ID of the request that killed the service (for reporting back).
150    */
151   uint64_t killing_client_request_id;
152
153   /**
154    * Process structure pointer of the child.
155    */
156   struct GNUNET_OS_Process *proc;
157
158   /**
159    * Process exponential backoff time
160    */
161   struct GNUNET_TIME_Relative backoff;
162
163   /**
164    * Absolute time at which the process is scheduled to restart in case of death
165    */
166   struct GNUNET_TIME_Absolute restart_at;
167
168   /**
169    * Time we asked the service to shut down (used to calculate time it took
170    * the service to terminate).
171    */
172   struct GNUNET_TIME_Absolute killed_at;
173
174   /**
175    * Is this service to be started by default (or did a client tell us explicitly
176    * to start it)?  #GNUNET_NO if the service is started only upon 'accept' on a
177    * listen socket or possibly explicitly by a client changing the value.
178    */
179   int force_start;
180
181   /**
182    * Should we use pipes to signal this process? (YES for Java binaries and if we
183    * are on Windoze).
184    */
185   int pipe_control;
186 };
187
188 /**
189  * List of running services.
190  */
191 static struct ServiceList *running_head;
192
193 /**
194  * List of running services.
195  */
196 static struct ServiceList *running_tail;
197
198 /**
199  * Our configuration
200  */
201 static const struct GNUNET_CONFIGURATION_Handle *cfg;
202
203 /**
204  * Command to prepend to each actual command.
205  */
206 static char *prefix_command;
207
208 /**
209  * Option to append to each actual command.
210  */
211 static char *final_option;
212
213 /**
214  * ID of task called whenever we get a SIGCHILD.
215  */
216 static struct GNUNET_SCHEDULER_Task *child_death_task;
217
218 /**
219  * ID of task called whenever the timeout for restarting a child
220  * expires.
221  */
222 static struct GNUNET_SCHEDULER_Task *child_restart_task;
223
224 /**
225  * Pipe used to communicate shutdown via signal.
226  */
227 static struct GNUNET_DISK_PipeHandle *sigpipe;
228
229 /**
230  * Are we in shutdown mode?
231  */
232 static int in_shutdown;
233
234 /**
235  * Are we starting user services?
236  */
237 static int start_user = GNUNET_YES;
238
239 /**
240  * Are we starting system services?
241  */
242 static int start_system = GNUNET_YES;
243
244 /**
245  * Handle to our server instance.  Our server is a bit special in that
246  * its service is not immediately stopped once we get a shutdown
247  * request (since we need to continue service until all of our child
248  * processes are dead).  This handle is used to shut down the server
249  * (and thus trigger process termination) once all child processes are
250  * also dead.  A special option in the ARM configuration modifies the
251  * behaviour of the service implementation to not do the shutdown
252  * immediately.
253  */
254 static struct GNUNET_SERVER_Handle *server;
255
256 /**
257  * Context for notifications we need to send to our clients.
258  */
259 static struct GNUNET_SERVER_NotificationContext *notifier;
260
261
262 /**
263  * Transmit a status result message.
264  *
265  * @param cls a `unit16_t *` with message type
266  * @param size number of bytes available in @a buf
267  * @param buf where to copy the message, NULL on error
268  * @return number of bytes copied to @a buf
269  */
270 static size_t
271 write_result (void *cls, size_t size, void *buf)
272 {
273   struct GNUNET_ARM_ResultMessage *msg = cls;
274   size_t msize;
275
276   if (NULL == buf)
277   {
278     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
279                 _("Could not send status result to client\n"));
280     GNUNET_free (msg);
281     return 0;                   /* error, not much we can do */
282   }
283   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
284               "Sending status response %u to client\n",
285               (unsigned int) msg->result);
286   msize = msg->arm_msg.header.size;
287   GNUNET_assert (size >= msize);
288   msg->arm_msg.header.size = htons (msg->arm_msg.header.size);
289   msg->arm_msg.header.type = htons (msg->arm_msg.header.type);
290   msg->result = htonl (msg->result);
291   msg->arm_msg.request_id = GNUNET_htonll (msg->arm_msg.request_id);
292   memcpy (buf, msg, msize);
293   GNUNET_free (msg);
294   return msize;
295 }
296
297
298 /**
299  * Transmit the list of running services.
300  *
301  * @param cls pointer to `struct GNUNET_ARM_ListResultMessage` with the message
302  * @param size number of bytes available in @a buf
303  * @param buf where to copy the message, NULL on error
304  * @return number of bytes copied to @a buf
305  */
306 static size_t
307 write_list_result (void *cls, size_t size, void *buf)
308 {
309   struct GNUNET_ARM_ListResultMessage *msg = cls;
310   size_t rslt_size;
311
312   if (NULL == buf)
313   {
314     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
315                 _("Could not send list result to client\n"));
316     GNUNET_free (msg);
317     return 0;                   /* error, not much we can do */
318   }
319
320   rslt_size = msg->arm_msg.header.size;
321   GNUNET_assert (size >= rslt_size);
322   msg->arm_msg.header.size = htons (msg->arm_msg.header.size);
323   msg->arm_msg.header.type = htons (msg->arm_msg.header.type);
324   msg->arm_msg.request_id = GNUNET_htonll (msg->arm_msg.request_id);
325   msg->count = htons (msg->count);
326
327   memcpy (buf, msg, rslt_size);
328   GNUNET_free (msg);
329   return rslt_size;
330 }
331
332
333 /**
334  * Signal our client that we will start or stop the
335  * service.
336  *
337  * @param client who is being signalled
338  * @param name name of the service
339  * @param request_id id of the request that is being responded to.
340  * @param result message type to send
341  * @return NULL if it was not found
342  */
343 static void
344 signal_result (struct GNUNET_SERVER_Client *client,
345                const char *name,
346                uint64_t request_id,
347                enum GNUNET_ARM_Result result)
348 {
349   struct GNUNET_ARM_ResultMessage *msg;
350   size_t msize;
351
352   msize = sizeof (struct GNUNET_ARM_ResultMessage);
353   msg = GNUNET_malloc (msize);
354   msg->arm_msg.header.size = msize;
355   msg->arm_msg.header.type = GNUNET_MESSAGE_TYPE_ARM_RESULT;
356   msg->result = result;
357   msg->arm_msg.request_id = request_id;
358
359   GNUNET_SERVER_notify_transmit_ready (client, msize,
360                                        GNUNET_TIME_UNIT_FOREVER_REL,
361                                        write_result, msg);
362 }
363
364
365 /**
366  * Tell all clients about status change of a service.
367  *
368  * @param name name of the service
369  * @param status message type to send
370  * @param unicast if not NULL, send to this client only.
371  *                otherwise, send to all clients in the notifier
372  */
373 static void
374 broadcast_status (const char *name,
375                   enum GNUNET_ARM_ServiceStatus status,
376                   struct GNUNET_SERVER_Client *unicast)
377 {
378   struct GNUNET_ARM_StatusMessage *msg;
379   size_t namelen;
380
381   if (NULL == notifier)
382     return;
383   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
384       "Sending status %u of service `%s' to client\n",
385       (unsigned int) status, name);
386   namelen = strlen (name);
387   msg = GNUNET_malloc (sizeof (struct GNUNET_ARM_StatusMessage) + namelen + 1);
388   msg->header.size = htons (sizeof (struct GNUNET_ARM_StatusMessage) + namelen + 1);
389   msg->header.type = htons (GNUNET_MESSAGE_TYPE_ARM_STATUS);
390   msg->status = htonl ((uint32_t) (status));
391   memcpy ((char *) &msg[1], name, namelen + 1);
392
393   if (NULL == unicast)
394     GNUNET_SERVER_notification_context_broadcast (notifier,
395         (struct GNUNET_MessageHeader *) msg, GNUNET_YES);
396   else
397     GNUNET_SERVER_notification_context_unicast (notifier, unicast,
398         (const struct GNUNET_MessageHeader *) msg, GNUNET_NO);
399   GNUNET_free (msg);
400 }
401
402
403 /**
404  * Actually start the process for the given service.
405  *
406  * @param sl identifies service to start
407  * @param client that asked to start the service (may be NULL)
408  * @param request_id id of the request in response to which the process is
409  *                   being started. 0 if starting was not requested.
410  */
411 static void
412 start_process (struct ServiceList *sl,
413                struct GNUNET_SERVER_Client *client,
414                uint64_t request_id)
415 {
416   char *loprefix;
417   char *options;
418   int use_debug;
419   int is_simple_service;
420   struct ServiceListeningInfo *sli;
421   SOCKTYPE *lsocks;
422   unsigned int ls;
423   char *binary;
424   char *quotedbinary;
425
426   /* calculate listen socket list */
427   lsocks = NULL;
428   ls = 0;
429   for (sli = sl->listen_head; NULL != sli; sli = sli->next)
430     {
431       GNUNET_array_append (lsocks, ls,
432                            GNUNET_NETWORK_get_fd (sli->listen_socket));
433       if (sli->accept_task != NULL)
434         {
435           GNUNET_SCHEDULER_cancel (sli->accept_task);
436           sli->accept_task = NULL;
437         }
438     }
439 #if WINDOWS
440   GNUNET_array_append (lsocks, ls, INVALID_SOCKET);
441 #else
442   GNUNET_array_append (lsocks, ls, -1);
443 #endif
444
445   /* obtain configuration */
446   if (GNUNET_OK !=
447       GNUNET_CONFIGURATION_get_value_string (cfg,
448                                              sl->name,
449                                              "PREFIX",
450                                              &loprefix))
451     loprefix = GNUNET_strdup (prefix_command);
452   if (GNUNET_OK !=
453       GNUNET_CONFIGURATION_get_value_string (cfg,
454                                              sl->name,
455                                              "OPTIONS",
456                                              &options))
457     options = NULL;
458
459   {
460     char *new_options;
461     char *optpos;
462     char *fin_options;
463
464     fin_options = GNUNET_strdup (final_option);
465     /* replace '{}' with service name */
466     while (NULL != (optpos = strstr (fin_options, "{}")))
467       {
468         /* terminate string at opening parenthesis */
469         *optpos = 0;
470         GNUNET_asprintf (&new_options,
471                          "%s%s%s",
472                          fin_options,
473                          sl->name,
474                          optpos + 2);
475         GNUNET_free (fin_options);
476         fin_options = new_options;
477       }
478     if (NULL != options)
479     {
480       /* combine "fin_options" with "options" */
481       optpos = options;
482       GNUNET_asprintf (&options,
483                        "%s %s",
484                        fin_options,
485                        optpos);
486       GNUNET_free (optpos);
487     }
488     else
489     {
490       /* only have "fin_options", use that */
491       options = fin_options;
492     }
493   }
494   options = GNUNET_CONFIGURATION_expand_dollar (cfg,
495                                                 options);
496   use_debug = GNUNET_CONFIGURATION_get_value_yesno (cfg,
497                                                     sl->name,
498                                                     "DEBUG");
499   {
500     const char *service_type = NULL;
501     const char *choices[] = { "GNUNET", "SIMPLE", NULL };
502
503     is_simple_service = GNUNET_NO;
504     if ( (GNUNET_OK ==
505           GNUNET_CONFIGURATION_get_value_choice (cfg,
506                                                  sl->name,
507                                                  "TYPE",
508                                                  choices,
509                                                  &service_type)) &&
510          (0 == strcasecmp (service_type, "SIMPLE")) )
511       is_simple_service = GNUNET_YES;
512   }
513
514   GNUNET_assert (NULL == sl->proc);
515   if (GNUNET_YES == is_simple_service)
516   {
517     /* A simple service will receive no GNUnet specific
518        command line options. */
519     binary = GNUNET_strdup (sl->binary);
520     binary = GNUNET_CONFIGURATION_expand_dollar (cfg, binary);
521     GNUNET_asprintf (&quotedbinary,
522                      "\"%s\"",
523                      sl->binary);
524     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
525                 "Starting simple service `%s' using binary `%s'\n",
526                 sl->name, sl->binary);
527     /* FIXME: dollar expansion should only be done outside
528      * of ''-quoted strings, escaping should be considered. */
529     if (NULL != options)
530       options = GNUNET_CONFIGURATION_expand_dollar (cfg, options);
531     sl->proc =
532       GNUNET_OS_start_process_s (sl->pipe_control,
533                                  GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
534                                  lsocks,
535                                  loprefix,
536                                  quotedbinary,
537                                  options,
538                                  NULL);
539   }
540   else
541   {
542     /* actually start process */
543     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
544                 "Starting service `%s' using binary `%s' and configuration `%s'\n",
545                 sl->name, sl->binary, sl->config);
546     binary = GNUNET_OS_get_libexec_binary_path (sl->binary);
547     GNUNET_asprintf (&quotedbinary,
548                      "\"%s\"",
549                      binary);
550
551     if (GNUNET_YES == use_debug)
552     {
553       if (NULL == sl->config)
554         sl->proc =
555           GNUNET_OS_start_process_s (sl->pipe_control,
556                                      GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
557                                      lsocks,
558                                      loprefix,
559                                      quotedbinary,
560                                      "-L", "DEBUG",
561                                      options,
562                                      NULL);
563       else
564         sl->proc =
565             GNUNET_OS_start_process_s (sl->pipe_control,
566                                        GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
567                                        lsocks,
568                                        loprefix,
569                                        quotedbinary,
570                                        "-c", sl->config,
571                                        "-L", "DEBUG",
572                                        options,
573                                        NULL);
574     }
575     else
576     {
577       if (NULL == sl->config)
578         sl->proc =
579             GNUNET_OS_start_process_s (sl->pipe_control,
580                                        GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
581                                        lsocks,
582                                        loprefix,
583                                        quotedbinary,
584                                        options,
585                                        NULL);
586       else
587         sl->proc =
588             GNUNET_OS_start_process_s (sl->pipe_control,
589                                        GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
590                                        lsocks,
591                                        loprefix,
592                                        quotedbinary,
593                                        "-c", sl->config,
594                                        options,
595                                        NULL);
596     }
597   }
598   GNUNET_free (binary);
599   GNUNET_free (quotedbinary);
600   if (sl->proc == NULL)
601   {
602     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
603                 _("Failed to start service `%s'\n"),
604                 sl->name);
605     if (client)
606       signal_result (client,
607                      sl->name,
608                      request_id,
609                      GNUNET_ARM_RESULT_START_FAILED);
610   }
611   else
612   {
613     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
614                 _("Starting service `%s'\n"),
615                 sl->name);
616     broadcast_status (sl->name, GNUNET_ARM_SERVICE_STARTING, NULL);
617     if (client)
618       signal_result (client, sl->name, request_id, GNUNET_ARM_RESULT_STARTING);
619   }
620   /* clean up */
621   GNUNET_free (loprefix);
622   GNUNET_free (options);
623   GNUNET_array_grow (lsocks, ls, 0);
624 }
625
626
627 /**
628  * Find the process with the given service
629  * name in the given list and return it.
630  *
631  * @param name which service entry to look up
632  * @return NULL if it was not found
633  */
634 static struct ServiceList *
635 find_service (const char *name)
636 {
637   struct ServiceList *sl;
638
639   sl = running_head;
640   while (sl != NULL)
641     {
642       if (0 == strcasecmp (sl->name, name))
643         return sl;
644       sl = sl->next;
645     }
646   return NULL;
647 }
648
649
650 /**
651  * First connection has come to the listening socket associated with the service,
652  * create the service in order to relay the incoming connection to it
653  *
654  * @param cls callback data, `struct ServiceListeningInfo` describing a listen socket
655  */
656 static void
657 accept_connection (void *cls)
658 {
659   struct ServiceListeningInfo *sli = cls;
660   struct ServiceList *sl = sli->sl;
661
662   sli->accept_task = NULL;
663   GNUNET_assert (GNUNET_NO == in_shutdown);
664   start_process (sl, NULL, 0);
665 }
666
667
668 /**
669  * Creating a listening socket for each of the service's addresses and
670  * wait for the first incoming connection to it
671  *
672  * @param sa address associated with the service
673  * @param addr_len length of @a sa
674  * @param sl service entry for the service in question
675  */
676 static void
677 create_listen_socket (struct sockaddr *sa,
678                       socklen_t addr_len,
679                       struct ServiceList *sl)
680 {
681   static int on = 1;
682   struct GNUNET_NETWORK_Handle *sock;
683   struct ServiceListeningInfo *sli;
684 #ifndef WINDOWS
685   int match_uid;
686   int match_gid;
687 #endif
688
689   switch (sa->sa_family)
690   {
691   case AF_INET:
692     sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
693     break;
694   case AF_INET6:
695     sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
696     break;
697   case AF_UNIX:
698     if (strcmp (GNUNET_a2s (sa, addr_len), "@") == 0)   /* Do not bind to blank UNIX path! */
699       return;
700     sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
701     break;
702   default:
703     GNUNET_break (0);
704     sock = NULL;
705     errno = EAFNOSUPPORT;
706     break;
707   }
708   if (NULL == sock)
709   {
710     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
711                 _("Unable to create socket for service `%s': %s\n"),
712                 sl->name, STRERROR (errno));
713     GNUNET_free (sa);
714     return;
715   }
716   if (GNUNET_NETWORK_socket_setsockopt
717       (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
718     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
719                          "setsockopt");
720 #ifdef IPV6_V6ONLY
721   if ((sa->sa_family == AF_INET6) &&
722       (GNUNET_NETWORK_socket_setsockopt
723        (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK))
724     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
725                          "setsockopt");
726 #endif
727 #ifndef WINDOWS
728   if (AF_UNIX == sa->sa_family)
729     GNUNET_NETWORK_unix_precheck ((struct sockaddr_un *) sa);
730 #endif
731   if (GNUNET_OK !=
732       GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) sa, addr_len))
733   {
734     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
735                 _("Unable to bind listening socket for service `%s' to address `%s': %s\n"),
736                 sl->name,
737                 GNUNET_a2s (sa, addr_len),
738                 STRERROR (errno));
739     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
740     GNUNET_free (sa);
741     return;
742   }
743 #ifndef WINDOWS
744   if ((AF_UNIX == sa->sa_family)
745 #ifdef LINUX
746       /* Permission settings are not required when abstract sockets are used */
747       && ('\0' != ((const struct sockaddr_un *)sa)->sun_path[0])
748 #endif
749       )
750   {
751     match_uid =
752       GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name,
753                                             "UNIX_MATCH_UID");
754     match_gid =
755       GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name,
756                                             "UNIX_MATCH_GID");
757     GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sa)->sun_path,
758                                  match_uid,
759                                  match_gid);
760
761   }
762 #endif
763   if (GNUNET_NETWORK_socket_listen (sock, 5) != GNUNET_OK)
764   {
765     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
766     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
767     GNUNET_free (sa);
768     return;
769   }
770   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
771               _("ARM now monitors connections to service `%s' at `%s'\n"),
772               sl->name, GNUNET_a2s (sa, addr_len));
773   sli = GNUNET_new (struct ServiceListeningInfo);
774   sli->service_addr = sa;
775   sli->service_addr_len = addr_len;
776   sli->listen_socket = sock;
777   sli->sl = sl;
778   sli->accept_task =
779     GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sock,
780                                    &accept_connection, sli);
781   GNUNET_CONTAINER_DLL_insert (sl->listen_head,
782                                sl->listen_tail,
783                                sli);
784 }
785
786
787 /**
788  * Remove and free an entry in the service list.  Listen sockets
789  * must have already been cleaned up.  Only to be called during shutdown.
790  *
791  * @param sl entry to free
792  */
793 static void
794 free_service (struct ServiceList *sl)
795 {
796   GNUNET_assert (GNUNET_YES == in_shutdown);
797   GNUNET_CONTAINER_DLL_remove (running_head, running_tail, sl);
798   GNUNET_assert (NULL == sl->listen_head);
799   GNUNET_free_non_null (sl->config);
800   GNUNET_free_non_null (sl->binary);
801   GNUNET_free (sl->name);
802   GNUNET_free (sl);
803 }
804
805
806 /**
807  * Handle START-message.
808  *
809  * @param cls closure (always NULL)
810  * @param client identification of the client
811  * @param message the actual message
812  * @return #GNUNET_OK to keep the connection open,
813  *         #GNUNET_SYSERR to close it (signal serious error)
814  */
815 static void
816 handle_start (void *cls,
817               struct GNUNET_SERVER_Client *client,
818               const struct GNUNET_MessageHeader *message)
819 {
820   const char *servicename;
821   struct ServiceList *sl;
822   uint16_t size;
823   uint64_t request_id;
824   struct GNUNET_ARM_Message *amsg;
825
826   amsg = (struct GNUNET_ARM_Message *) message;
827   request_id = GNUNET_ntohll (amsg->request_id);
828   size = ntohs (amsg->header.size);
829   size -= sizeof (struct GNUNET_ARM_Message);
830   servicename = (const char *) &amsg[1];
831   if ((size == 0) || (servicename[size - 1] != '\0'))
832   {
833     GNUNET_break (0);
834     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
835     return;
836   }
837   if (GNUNET_YES == in_shutdown)
838   {
839     signal_result (client, servicename, request_id,
840                    GNUNET_ARM_RESULT_IN_SHUTDOWN);
841     GNUNET_SERVER_receive_done (client, GNUNET_OK);
842     return;
843   }
844   sl = find_service (servicename);
845   if (NULL == sl)
846   {
847     signal_result (client, servicename, request_id,
848                    GNUNET_ARM_RESULT_IS_NOT_KNOWN);
849     GNUNET_SERVER_receive_done (client, GNUNET_OK);
850     return;
851   }
852   sl->force_start = GNUNET_YES;
853   if (NULL != sl->proc)
854   {
855     signal_result (client, servicename, request_id,
856                    GNUNET_ARM_RESULT_IS_STARTED_ALREADY);
857     GNUNET_SERVER_receive_done (client, GNUNET_OK);
858     return;
859   }
860   start_process (sl, client, request_id);
861   GNUNET_SERVER_receive_done (client, GNUNET_OK);
862 }
863
864
865 /**
866  * Start a shutdown sequence.
867  *
868  * @param cls closure (refers to service)
869  */
870 static void
871 trigger_shutdown (void *cls)
872 {
873   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
874               "Triggering shutdown\n");
875   GNUNET_SCHEDULER_shutdown ();
876 }
877
878
879 /**
880  * Handle STOP-message.
881  *
882  * @param cls closure (always NULL)
883  * @param client identification of the client
884  * @param message the actual message
885  * @return #GNUNET_OK to keep the connection open,
886  *         #GNUNET_SYSERR to close it (signal serious error)
887  */
888 static void
889 handle_stop (void *cls,
890              struct GNUNET_SERVER_Client *client,
891              const struct GNUNET_MessageHeader *message)
892 {
893   struct ServiceList *sl;
894   const char *servicename;
895   uint16_t size;
896   uint64_t request_id;
897   struct GNUNET_ARM_Message *amsg;
898
899   amsg = (struct GNUNET_ARM_Message *) message;
900   request_id = GNUNET_ntohll (amsg->request_id);
901   size = ntohs (amsg->header.size);
902   size -= sizeof (struct GNUNET_ARM_Message);
903   servicename = (const char *) &amsg[1];
904   if ((size == 0) || (servicename[size - 1] != '\0'))
905     {
906       GNUNET_break (0);
907       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
908       return;
909     }
910   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
911               _("Preparing to stop `%s'\n"),
912               servicename);
913   if (0 == strcasecmp (servicename, "arm"))
914   {
915     broadcast_status (servicename,
916                       GNUNET_ARM_SERVICE_STOPPING, NULL);
917     signal_result (client,
918                    servicename,
919                    request_id,
920                    GNUNET_ARM_RESULT_STOPPING);
921     GNUNET_SERVER_client_persist_ (client);
922     GNUNET_SCHEDULER_add_now (&trigger_shutdown, NULL);
923     GNUNET_SERVER_receive_done (client, GNUNET_OK);
924     return;
925   }
926   sl = find_service (servicename);
927   if (sl == NULL)
928     {
929       signal_result (client,
930                      servicename,
931                      request_id,
932                      GNUNET_ARM_RESULT_IS_NOT_KNOWN);
933       GNUNET_SERVER_receive_done (client, GNUNET_OK);
934       return;
935     }
936   sl->force_start = GNUNET_NO;
937   if (GNUNET_YES == in_shutdown)
938     {
939       /* shutdown in progress */
940       signal_result (client,
941                      servicename,
942                      request_id,
943                      GNUNET_ARM_RESULT_IN_SHUTDOWN);
944       GNUNET_SERVER_receive_done (client, GNUNET_OK);
945       return;
946     }
947   if (NULL != sl->killing_client)
948   {
949     /* killing already in progress */
950     signal_result (client,
951                    servicename,
952                    request_id,
953                    GNUNET_ARM_RESULT_IS_STOPPING_ALREADY);
954     GNUNET_SERVER_receive_done (client, GNUNET_OK);
955     return;
956   }
957   if (NULL == sl->proc)
958   {
959     /* process is down */
960     signal_result (client,
961                    servicename,
962                    request_id,
963                    GNUNET_ARM_RESULT_IS_STOPPED_ALREADY);
964     GNUNET_SERVER_receive_done (client, GNUNET_OK);
965     return;
966   }
967   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
968               "Sending kill signal to service `%s', waiting for process to die.\n",
969               servicename);
970   broadcast_status (servicename,
971                     GNUNET_ARM_SERVICE_STOPPING,
972                     NULL);
973   /* no signal_start - only when it's STOPPED */
974   sl->killed_at = GNUNET_TIME_absolute_get ();
975   if (0 != GNUNET_OS_process_kill (sl->proc, GNUNET_TERM_SIG))
976     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
977   sl->killing_client = client;
978   sl->killing_client_request_id = request_id;
979   GNUNET_SERVER_client_keep (client);
980   GNUNET_SERVER_receive_done (client, GNUNET_OK);
981 }
982
983
984 /**
985  * Handle LIST-message.
986  *
987  * @param cls closure (always NULL)
988  * @param client identification of the client
989  * @param message the actual message
990  */
991 static void
992 handle_list (void *cls, struct GNUNET_SERVER_Client *client,
993              const struct GNUNET_MessageHeader *message)
994 {
995   struct GNUNET_ARM_ListResultMessage *msg;
996   struct GNUNET_ARM_Message *request;
997   size_t string_list_size;
998   size_t total_size;
999   struct ServiceList *sl;
1000   uint16_t count;
1001
1002   if (NULL == client)
1003     return;
1004
1005   request = (struct GNUNET_ARM_Message *) message;
1006   GNUNET_break (0 == ntohl (request->reserved));
1007   count = 0;
1008   string_list_size = 0;
1009   /* first count the running processes get their name's size */
1010   for (sl = running_head; NULL != sl; sl = sl->next)
1011   {
1012     if (NULL != sl->proc)
1013     {
1014       string_list_size += strlen (sl->name);
1015       string_list_size += strlen (sl->binary);
1016       string_list_size += 4;
1017       count++;
1018     }
1019   }
1020
1021   total_size = sizeof (struct GNUNET_ARM_ListResultMessage)
1022                + string_list_size;
1023   msg = GNUNET_malloc (total_size);
1024   msg->arm_msg.header.size = total_size;
1025   msg->arm_msg.header.type = GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT;
1026   msg->arm_msg.reserved = htonl (0);
1027   msg->arm_msg.request_id = GNUNET_ntohll (request->request_id);
1028   msg->count = count;
1029
1030   char *pos = (char *)&msg[1];
1031   for (sl = running_head; NULL != sl; sl = sl->next)
1032   {
1033     if (NULL != sl->proc)
1034     {
1035       size_t s = strlen (sl->name) + strlen (sl->binary) + 4;
1036       GNUNET_snprintf (pos, s, "%s (%s)", sl->name, sl->binary);
1037       pos += s;
1038     }
1039   }
1040   GNUNET_SERVER_notify_transmit_ready (client,
1041                                        total_size,
1042                                        GNUNET_TIME_UNIT_FOREVER_REL,
1043                                        &write_list_result, msg);
1044   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1045 }
1046
1047
1048 /**
1049  * We are done with everything.  Stop remaining
1050  * tasks, signal handler and the server.
1051  */
1052 static void
1053 do_shutdown ()
1054 {
1055   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Last shutdown phase\n");
1056   if (NULL != notifier)
1057   {
1058     GNUNET_SERVER_notification_context_destroy (notifier);
1059     notifier = NULL;
1060   }
1061   if (NULL != server)
1062     {
1063       GNUNET_SERVER_destroy (server);
1064       server = NULL;
1065     }
1066   if (NULL != child_death_task)
1067     {
1068       GNUNET_SCHEDULER_cancel (child_death_task);
1069       child_death_task = NULL;
1070     }
1071 }
1072
1073
1074 /**
1075  * Count how many services are still active.
1076  *
1077  * @param running_head list of services
1078  * @return number of active services found
1079  */
1080 static unsigned int
1081 list_count (struct ServiceList *running_head)
1082 {
1083   struct ServiceList *i;
1084   unsigned int res = 0;
1085
1086   for (res = 0, i = running_head; i; i = i->next, res++)
1087     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1088                 "%s\n",
1089                 i->name);
1090   return res;
1091 }
1092
1093
1094 /**
1095  * Task run for shutdown.
1096  *
1097  * @param cls closure, NULL if we need to self-restart
1098  */
1099 static void
1100 shutdown_task (void *cls)
1101 {
1102   struct ServiceList *pos;
1103   struct ServiceList *nxt;
1104   struct ServiceListeningInfo *sli;
1105
1106   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1107               "First shutdown phase\n");
1108   if (NULL != child_restart_task)
1109   {
1110     GNUNET_SCHEDULER_cancel (child_restart_task);
1111     child_restart_task = NULL;
1112   }
1113   in_shutdown = GNUNET_YES;
1114   /* first, stop listening */
1115   for (pos = running_head; NULL != pos; pos = pos->next)
1116   {
1117     while (NULL != (sli = pos->listen_head))
1118       {
1119         GNUNET_CONTAINER_DLL_remove (pos->listen_head,
1120                                      pos->listen_tail,
1121                                      sli);
1122         if (NULL != sli->accept_task)
1123           {
1124             GNUNET_SCHEDULER_cancel (sli->accept_task);
1125             sli->accept_task = NULL;
1126           }
1127         GNUNET_break (GNUNET_OK ==
1128                       GNUNET_NETWORK_socket_close (sli->listen_socket));
1129         GNUNET_free (sli->service_addr);
1130         GNUNET_free (sli);
1131       }
1132   }
1133   /* then, shutdown all existing service processes */
1134   nxt = running_head;
1135   while (NULL != (pos = nxt))
1136   {
1137     nxt = pos->next;
1138     if (NULL != pos->proc)
1139     {
1140       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1141                   "Stopping service `%s'\n",
1142                   pos->name);
1143       pos->killed_at = GNUNET_TIME_absolute_get ();
1144       if (0 != GNUNET_OS_process_kill (pos->proc, GNUNET_TERM_SIG))
1145         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
1146     }
1147     else
1148     {
1149       free_service (pos);
1150     }
1151   }
1152   /* finally, should all service processes be already gone, terminate for real */
1153   if (NULL == running_head)
1154     do_shutdown ();
1155   else
1156     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1157                 "Delaying shutdown, have %u childs still running\n",
1158                 list_count (running_head));
1159 }
1160
1161
1162 /**
1163  * Task run whenever it is time to restart a child that died.
1164  *
1165  * @param cls closure, always NULL
1166  */
1167 static void
1168 delayed_restart_task (void *cls)
1169
1170 {
1171   struct ServiceList *sl;
1172   struct GNUNET_TIME_Relative lowestRestartDelay;
1173   struct ServiceListeningInfo *sli;
1174
1175   child_restart_task = NULL;
1176   GNUNET_assert (GNUNET_NO == in_shutdown);
1177   lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL;
1178
1179   /* check for services that need to be restarted due to
1180    * configuration changes or because the last restart failed */
1181   for (sl = running_head; NULL != sl; sl = sl->next)
1182   {
1183     if (NULL != sl->proc)
1184       continue;
1185     /* service is currently not running */
1186     if (0 == GNUNET_TIME_absolute_get_remaining (sl->restart_at).rel_value_us)
1187     {
1188       /* restart is now allowed */
1189       if (sl->force_start)
1190       {
1191         /* process should run by default, start immediately */
1192         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1193                     _("Restarting service `%s'.\n"),
1194                     sl->name);
1195         start_process (sl, NULL, 0);
1196       }
1197       else
1198       {
1199         /* process is run on-demand, ensure it is re-started if there is demand */
1200         for (sli = sl->listen_head; NULL != sli; sli = sli->next)
1201           if (NULL == sli->accept_task)
1202           {
1203             /* accept was actually paused, so start it again */
1204             sli->accept_task =
1205               GNUNET_SCHEDULER_add_read_net
1206               (GNUNET_TIME_UNIT_FOREVER_REL,
1207                sli->listen_socket,
1208                &accept_connection, sli);
1209           }
1210       }
1211     }
1212     else
1213     {
1214       /* update calculation for earliest time to reactivate a service */
1215       lowestRestartDelay =
1216         GNUNET_TIME_relative_min (lowestRestartDelay,
1217                                   GNUNET_TIME_absolute_get_remaining
1218                                   (sl->restart_at));
1219     }
1220   }
1221   if (lowestRestartDelay.rel_value_us != GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1222   {
1223     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1224                 "Will restart process in %s\n",
1225                 GNUNET_STRINGS_relative_time_to_string (lowestRestartDelay, GNUNET_YES));
1226     child_restart_task =
1227       GNUNET_SCHEDULER_add_delayed_with_priority (lowestRestartDelay,
1228                                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
1229                                                   &delayed_restart_task, NULL);
1230   }
1231 }
1232
1233
1234 /**
1235  * Task triggered whenever we receive a SIGCHLD (child
1236  * process died).
1237  *
1238  * @param cls closure, NULL if we need to self-restart
1239  */
1240 static void
1241 maint_child_death (void *cls)
1242 {
1243   struct ServiceList *pos;
1244   struct ServiceList *next;
1245   struct ServiceListeningInfo *sli;
1246   const char *statstr;
1247   int statcode;
1248   int ret;
1249   char c[16];
1250   enum GNUNET_OS_ProcessStatusType statusType;
1251   unsigned long statusCode;
1252   const struct GNUNET_DISK_FileHandle *pr;
1253
1254   pr = GNUNET_DISK_pipe_handle (sigpipe,
1255                                 GNUNET_DISK_PIPE_END_READ);
1256   child_death_task = NULL;
1257   /* consume the signal */
1258   GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
1259
1260   /* check for services that died (WAITPID) */
1261   next = running_head;
1262   while (NULL != (pos = next))
1263   {
1264     next = pos->next;
1265
1266     if (NULL == pos->proc)
1267     {
1268       if (GNUNET_YES == in_shutdown)
1269         free_service (pos);
1270       continue;
1271     }
1272 #if HAVE_WAIT4
1273     if (NULL != wait_file)
1274     {
1275       /* need to use 'wait4()' to obtain and log performance data */
1276       struct rusage ru;
1277       int status;
1278       pid_t pid;
1279
1280       pid = GNUNET_OS_process_get_pid (pos->proc);
1281       ret = wait4 (pid,
1282                    &status,
1283                    WNOHANG,
1284                    &ru);
1285       if (ret <= 0)
1286         continue; /* no process done */
1287       if (WIFEXITED (status))
1288       {
1289         statusType = GNUNET_OS_PROCESS_EXITED;
1290         statusCode = WEXITSTATUS (status);
1291       }
1292       else if (WIFSIGNALED (status))
1293       {
1294         statusType = GNUNET_OS_PROCESS_SIGNALED;
1295         statusCode = WTERMSIG (status);
1296       }
1297       else if (WIFSTOPPED (status))
1298       {
1299         statusType = GNUNET_OS_PROCESS_SIGNALED;
1300         statusCode = WSTOPSIG (status);
1301       }
1302 #ifdef WIFCONTINUED
1303       else if (WIFCONTINUED (status))
1304       {
1305         statusType = GNUNET_OS_PROCESS_RUNNING;
1306         statusCode = 0;
1307       }
1308 #endif
1309       else
1310       {
1311         statusType = GNUNET_OS_PROCESS_UNKNOWN;
1312         statusCode = 0;
1313       }
1314       if ( (GNUNET_OS_PROCESS_EXITED == statusType) ||
1315            (GNUNET_OS_PROCESS_SIGNALED == statusType) )
1316       {
1317         double utime = ru.ru_utime.tv_sec + (ru.ru_utime.tv_usec / 10e6);
1318         double stime = ru.ru_stime.tv_sec + (ru.ru_stime.tv_usec / 10e6);
1319         fprintf (wait_file,
1320                  "%s(%u) %.3f %.3f %llu %llu %llu %llu %llu\n",
1321                  pos->binary,
1322                  (unsigned int) pid,
1323                  utime,
1324                  stime,
1325                  (unsigned long long) ru.ru_maxrss,
1326                  (unsigned long long) ru.ru_inblock,
1327                  (unsigned long long) ru.ru_oublock,
1328                  (unsigned long long) ru.ru_nvcsw,
1329                  (unsigned long long) ru.ru_nivcsw);
1330       }
1331     }
1332     else /* continue with JUST this "if" as "else" (intentionally no brackets!) */
1333 #endif
1334     if ( (GNUNET_SYSERR ==
1335           (ret =
1336            GNUNET_OS_process_status (pos->proc,
1337                                      &statusType,
1338                                      &statusCode))) ||
1339          (ret == GNUNET_NO) ||
1340          (statusType == GNUNET_OS_PROCESS_STOPPED) ||
1341          (statusType == GNUNET_OS_PROCESS_UNKNOWN) ||
1342          (statusType == GNUNET_OS_PROCESS_RUNNING) )
1343       continue;
1344
1345     if (statusType == GNUNET_OS_PROCESS_EXITED)
1346     {
1347       statstr = _( /* process termination method */ "exit");
1348       statcode = statusCode;
1349     }
1350     else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
1351     {
1352       statstr = _( /* process termination method */ "signal");
1353       statcode = statusCode;
1354     }
1355     else
1356     {
1357       statstr = _( /* process termination method */ "unknown");
1358       statcode = 0;
1359     }
1360     if (0 != pos->killed_at.abs_value_us)
1361     {
1362       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1363                   _("Service `%s' took %s to terminate\n"),
1364                   pos->name,
1365                   GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->killed_at),
1366                                                           GNUNET_YES));
1367     }
1368     GNUNET_OS_process_destroy (pos->proc);
1369     pos->proc = NULL;
1370     broadcast_status (pos->name,
1371                       GNUNET_ARM_SERVICE_STOPPED,
1372                       NULL);
1373     if (NULL != pos->killing_client)
1374     {
1375       signal_result (pos->killing_client, pos->name,
1376                      pos->killing_client_request_id,
1377                      GNUNET_ARM_RESULT_STOPPED);
1378       GNUNET_SERVER_client_drop (pos->killing_client);
1379       pos->killing_client = NULL;
1380       pos->killing_client_request_id = 0;
1381     }
1382     if (GNUNET_YES != in_shutdown)
1383     {
1384       if ( (statusType == GNUNET_OS_PROCESS_EXITED) &&
1385            (statcode == 0) )
1386       {
1387         /* process terminated normally, allow restart at any time */
1388         pos->restart_at.abs_value_us = 0;
1389         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1390                     _("Service `%s' terminated normally, will restart at any time\n"),
1391                     pos->name);
1392         /* process can still be re-started on-demand, ensure it is re-started if there is demand */
1393         for (sli = pos->listen_head; NULL != sli; sli = sli->next)
1394         {
1395           GNUNET_break (NULL == sli->accept_task);
1396           sli->accept_task =
1397             GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1398                                            sli->listen_socket,
1399                                            &accept_connection,
1400                                            sli);
1401         }
1402       }
1403       else
1404       {
1405         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1406                     _("Service `%s' terminated with status %s/%d, will restart in %s\n"),
1407                     pos->name,
1408                     statstr,
1409                     statcode,
1410                     GNUNET_STRINGS_relative_time_to_string (pos->backoff,
1411                                                             GNUNET_YES));
1412         /* schedule restart */
1413         pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff);
1414         pos->backoff = GNUNET_TIME_STD_BACKOFF (pos->backoff);
1415         if (NULL != child_restart_task)
1416           GNUNET_SCHEDULER_cancel (child_restart_task);
1417         child_restart_task
1418           = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
1419                                                 &delayed_restart_task,
1420                                                 NULL);
1421       }
1422     }
1423     else
1424     {
1425       free_service (pos);
1426     }
1427   }
1428   child_death_task = GNUNET_SCHEDULER_add_read_file (
1429       GNUNET_TIME_UNIT_FOREVER_REL,
1430       pr,
1431       &maint_child_death, NULL);
1432   if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
1433     do_shutdown ();
1434   else if (GNUNET_YES == in_shutdown)
1435     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1436         "Delaying shutdown after child's death, still have %u children\n",
1437         list_count (running_head));
1438
1439 }
1440
1441
1442 /**
1443  * Signal handler called for SIGCHLD.  Triggers the
1444  * respective handler by writing to the trigger pipe.
1445  */
1446 static void
1447 sighandler_child_death ()
1448 {
1449   static char c;
1450   int old_errno = errno;        /* back-up errno */
1451
1452   GNUNET_break (1 ==
1453                 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
1454                                         (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
1455                                         &c, sizeof (c)));
1456   errno = old_errno;            /* restore errno */
1457 }
1458
1459
1460 /**
1461  * Setup our service record for the given section in the configuration file
1462  * (assuming the section is for a service).
1463  *
1464  * @param cls unused
1465  * @param section a section in the configuration file
1466  * @return #GNUNET_OK (continue)
1467  */
1468 static void
1469 setup_service (void *cls,
1470                const char *section)
1471 {
1472   struct ServiceList *sl;
1473   char *binary;
1474   char *config;
1475   struct stat sbuf;
1476   struct sockaddr **addrs;
1477   socklen_t *addr_lens;
1478   int ret;
1479   unsigned int i;
1480
1481   if (strcasecmp (section, "arm") == 0)
1482     return;
1483   if (GNUNET_OK !=
1484       GNUNET_CONFIGURATION_get_value_string (cfg, section, "BINARY", &binary))
1485   {
1486     /* not a service section */
1487     return;
1488   }
1489   if ((GNUNET_YES ==
1490        GNUNET_CONFIGURATION_have_value (cfg, section, "USER_SERVICE")) &&
1491       (GNUNET_YES ==
1492        GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "USER_SERVICE")))
1493   {
1494     if (GNUNET_NO == start_user)
1495     {
1496       GNUNET_free (binary);
1497       return; /* user service, and we don't deal with those */
1498     }
1499   }
1500   else
1501   {
1502     if (GNUNET_NO == start_system)
1503     {
1504       GNUNET_free (binary);
1505       return; /* system service, and we don't deal with those */
1506     }
1507   }
1508   sl = find_service (section);
1509   if (NULL != sl)
1510   {
1511     /* got the same section twice!? */
1512     GNUNET_break (0);
1513     GNUNET_free (binary);
1514     return;
1515   }
1516   config = NULL;
1517   if (( (GNUNET_OK !=
1518          GNUNET_CONFIGURATION_get_value_filename (cfg, section,
1519                                                   "CONFIG",
1520                                                   &config)) &&
1521         (GNUNET_OK !=
1522          GNUNET_CONFIGURATION_get_value_filename (cfg,
1523                                                   "PATHS",
1524                                                   "DEFAULTCONFIG",
1525                                                   &config)) ) ||
1526       (0 != STAT (config, &sbuf)))
1527   {
1528     if (NULL != config)
1529     {
1530       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1531                                  section, "CONFIG",
1532                                  STRERROR (errno));
1533       GNUNET_free (config);
1534       config = NULL;
1535     }
1536   }
1537   sl = GNUNET_new (struct ServiceList);
1538   sl->name = GNUNET_strdup (section);
1539   sl->binary = binary;
1540   sl->config = config;
1541   sl->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
1542   sl->restart_at = GNUNET_TIME_UNIT_FOREVER_ABS;
1543 #if WINDOWS
1544   sl->pipe_control = GNUNET_YES;
1545 #else
1546   if (GNUNET_CONFIGURATION_have_value (cfg,
1547                                        section,
1548                                        "PIPECONTROL"))
1549     sl->pipe_control = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1550                                                              section,
1551                                                              "PIPECONTROL");
1552 #endif
1553   GNUNET_CONTAINER_DLL_insert (running_head,
1554                                running_tail,
1555                                sl);
1556   if (GNUNET_YES ==
1557       GNUNET_CONFIGURATION_get_value_yesno (cfg,
1558                                             section,
1559                                             "FORCESTART"))
1560   {
1561     sl->force_start = GNUNET_YES;
1562     if (GNUNET_YES ==
1563         GNUNET_CONFIGURATION_get_value_yesno (cfg,
1564                                               section,
1565                                               "NOARMBIND"))
1566       return;
1567   }
1568   else
1569   {
1570     if (GNUNET_YES !=
1571         GNUNET_CONFIGURATION_get_value_yesno (cfg,
1572                                               section,
1573                                               "AUTOSTART"))
1574       return;
1575   }
1576   if (0 >= (ret = GNUNET_SERVICE_get_server_addresses (section,
1577                                                        cfg,
1578                                                        &addrs,
1579                                                        &addr_lens)))
1580     return;
1581   /* this will free (or capture) addrs[i] */
1582   for (i = 0; i < ret; i++)
1583     create_listen_socket (addrs[i],
1584                           addr_lens[i],
1585                           sl);
1586   GNUNET_free (addrs);
1587   GNUNET_free (addr_lens);
1588 }
1589
1590
1591 /**
1592  * A client connected, add it to the notification context.
1593  *
1594  * @param cls closure
1595  * @param client identification of the client
1596  */
1597 static void
1598 handle_client_connecting (void *cls, struct GNUNET_SERVER_Client *client)
1599 {
1600   /* All clients are considered to be of the "monitor" kind
1601    * (that is, they don't affect ARM shutdown).
1602    */
1603   if (NULL != client)
1604     GNUNET_SERVER_client_mark_monitor (client);
1605 }
1606
1607
1608 /**
1609  * Handle MONITOR-message.
1610  *
1611  * @param cls closure (always NULL)
1612  * @param client identification of the client
1613  * @param message the actual message
1614  * @return #GNUNET_OK to keep the connection open,
1615  *         #GNUNET_SYSERR to close it (signal serious error)
1616  */
1617 static void
1618 handle_monitor (void *cls, struct GNUNET_SERVER_Client *client,
1619              const struct GNUNET_MessageHeader *message)
1620 {
1621   /* Removal is handled by the server implementation, internally. */
1622   if ((NULL != client) && (NULL != notifier))
1623   {
1624     GNUNET_SERVER_notification_context_add (notifier, client);
1625     broadcast_status ("arm", GNUNET_ARM_SERVICE_MONITORING_STARTED, client);
1626     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1627   }
1628 }
1629
1630
1631 /**
1632  * Process arm requests.
1633  *
1634  * @param cls closure
1635  * @param serv the initialized server
1636  * @param c configuration to use
1637  */
1638 static void
1639 run (void *cls, struct GNUNET_SERVER_Handle *serv,
1640      const struct GNUNET_CONFIGURATION_Handle *c)
1641 {
1642   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1643     {&handle_start, NULL, GNUNET_MESSAGE_TYPE_ARM_START, 0},
1644     {&handle_stop, NULL, GNUNET_MESSAGE_TYPE_ARM_STOP, 0},
1645     {&handle_monitor, NULL, GNUNET_MESSAGE_TYPE_ARM_MONITOR,
1646      sizeof (struct GNUNET_MessageHeader)},
1647     {&handle_list, NULL, GNUNET_MESSAGE_TYPE_ARM_LIST,
1648      sizeof (struct GNUNET_ARM_Message)},
1649     {NULL, NULL, 0, 0}
1650   };
1651   struct ServiceList *sl;
1652
1653   cfg = c;
1654   server = serv;
1655   GNUNET_assert (NULL != serv);
1656   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1657                                  NULL);
1658   child_death_task =
1659     GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1660                                     GNUNET_DISK_pipe_handle (sigpipe,
1661                                                              GNUNET_DISK_PIPE_END_READ),
1662                                     &maint_child_death, NULL);
1663 #if HAVE_WAIT4
1664   if (GNUNET_OK ==
1665       GNUNET_CONFIGURATION_get_value_filename (cfg,
1666                                                "ARM",
1667                                                "RESOURCE_DIAGNOSTICS",
1668                                                &wait_filename))
1669   {
1670     wait_file = fopen (wait_filename,
1671                        "w");
1672     if (NULL == wait_file)
1673     {
1674       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1675                                 "fopen",
1676                                 wait_filename);
1677     }
1678   }
1679 #endif
1680   if (GNUNET_OK !=
1681       GNUNET_CONFIGURATION_get_value_string (cfg,
1682                                              "ARM",
1683                                              "GLOBAL_PREFIX",
1684                                              &prefix_command))
1685     prefix_command = GNUNET_strdup ("");
1686   if (GNUNET_OK !=
1687       GNUNET_CONFIGURATION_get_value_string (cfg,
1688                                              "ARM",
1689                                              "GLOBAL_POSTFIX",
1690                                              &final_option))
1691     final_option = GNUNET_strdup ("");
1692   if (GNUNET_YES ==
1693       GNUNET_CONFIGURATION_get_value_yesno (cfg,
1694                                             "ARM",
1695                                             "USER_ONLY"))
1696   {
1697     GNUNET_break (GNUNET_YES == start_user);
1698     start_system = GNUNET_NO;
1699   }
1700   if (GNUNET_YES ==
1701       GNUNET_CONFIGURATION_get_value_yesno (cfg,
1702                                             "ARM",
1703                                             "SYSTEM_ONLY"))
1704   {
1705     GNUNET_break (GNUNET_YES == start_system);
1706     start_user = GNUNET_NO;
1707   }
1708   GNUNET_CONFIGURATION_iterate_sections (cfg, &setup_service, NULL);
1709
1710   /* start default services... */
1711   for (sl = running_head; NULL != sl; sl = sl->next)
1712     if (GNUNET_YES == sl->force_start)
1713       start_process (sl, NULL, 0);
1714   notifier
1715     = GNUNET_SERVER_notification_context_create (server,
1716                                                  MAX_NOTIFY_QUEUE);
1717   GNUNET_SERVER_connect_notify (server,
1718                                 &handle_client_connecting, NULL);
1719   /* process client requests */
1720   GNUNET_SERVER_add_handlers (server,
1721                               handlers);
1722 }
1723
1724
1725 /**
1726  * The main function for the arm service.
1727  *
1728  * @param argc number of arguments from the command line
1729  * @param argv command line arguments
1730  * @return 0 ok, 1 on error
1731  */
1732 int
1733 main (int argc, char *const *argv)
1734 {
1735   int ret;
1736   struct GNUNET_SIGNAL_Context *shc_chld;
1737
1738   sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
1739   GNUNET_assert (sigpipe != NULL);
1740   shc_chld =
1741     GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
1742   ret =
1743     (GNUNET_OK ==
1744      GNUNET_SERVICE_run (argc, argv, "arm",
1745                          GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN, &run, NULL)) ? 0 : 1;
1746 #if HAVE_WAIT4
1747   if (NULL != wait_file)
1748   {
1749     fclose (wait_file);
1750     wait_file = NULL;
1751   }
1752   if (NULL != wait_filename)
1753   {
1754     GNUNET_free (wait_filename);
1755     wait_filename = NULL;
1756   }
1757 #endif
1758   GNUNET_SIGNAL_handler_uninstall (shc_chld);
1759   shc_chld = NULL;
1760   GNUNET_DISK_pipe_close (sigpipe);
1761   sigpipe = NULL;
1762   return ret;
1763 }
1764
1765
1766 #if defined(LINUX) && defined(__GLIBC__)
1767 #include <malloc.h>
1768
1769 /**
1770  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1771  */
1772 void __attribute__ ((constructor)) GNUNET_ARM_memory_init ()
1773 {
1774   mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1775   mallopt (M_TOP_PAD, 1 * 1024);
1776   malloc_trim (0);
1777 }
1778 #endif
1779
1780
1781 /* end of gnunet-service-arm.c */