fix compiler warnings
[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, sl->name, "PREFIX",
448                                              &loprefix))
449     loprefix = GNUNET_strdup (prefix_command);
450   if (GNUNET_OK !=
451       GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "OPTIONS",
452                                              &options))
453     {
454       char *new_options;
455       char *optpos;
456       options = GNUNET_strdup (final_option);
457       /* replace '{}' with service name */
458       while (NULL != (optpos = strstr (options, "{}")))
459         {
460           /* terminate string at opening parenthesis */
461           *optpos = 0;
462           GNUNET_asprintf (&new_options, "%s%s%s", options, sl->name, optpos + 2);
463           GNUNET_free (options);
464           options = new_options;
465         }
466       options = GNUNET_CONFIGURATION_expand_dollar (cfg, options);
467     }
468   use_debug = GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name, "DEBUG");
469
470   {
471     const char *service_type = NULL;
472     const char *choices[] = { "GNUNET", "SIMPLE", NULL };
473     is_simple_service = GNUNET_NO;
474     if ( (GNUNET_OK ==
475             GNUNET_CONFIGURATION_get_value_choice (cfg,
476                                                    sl->name,
477                                                    "TYPE",
478                                                    choices,
479                                                    &service_type)) &&
480          (0 == strcasecmp (service_type, "SIMPLE")) )
481       is_simple_service = GNUNET_YES;
482   }
483
484   GNUNET_assert (NULL == sl->proc);
485   if (GNUNET_YES == is_simple_service)
486   {
487     /* A simple service will receive no GNUnet specific
488        command line options. */
489     binary = GNUNET_strdup (sl->binary);
490     binary = GNUNET_CONFIGURATION_expand_dollar (cfg, binary);
491     GNUNET_asprintf (&quotedbinary,
492                      "\"%s\"",
493                      sl->binary);
494     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
495                 "Starting simple service `%s' using binary `%s'\n",
496                 sl->name, sl->binary);
497     /* FIXME: dollar expansion should only be done outside
498      * of ''-quoted strings, escaping should be considered. */
499     if (NULL != options)
500       options = GNUNET_CONFIGURATION_expand_dollar (cfg, options);
501     sl->proc =
502       GNUNET_OS_start_process_s (sl->pipe_control,
503                                  GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
504                                  lsocks, loprefix, quotedbinary,
505                                  options, NULL);
506   }
507   else
508   {
509     /* actually start process */
510     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
511                 "Starting service `%s' using binary `%s' and configuration `%s'\n",
512                 sl->name, sl->binary, sl->config);
513     binary = GNUNET_OS_get_libexec_binary_path (sl->binary);
514     GNUNET_asprintf (&quotedbinary,
515                      "\"%s\"",
516                      binary);
517
518     if (GNUNET_YES == use_debug)
519     {
520       if (NULL == sl->config)
521         sl->proc =
522           GNUNET_OS_start_process_s (sl->pipe_control,
523                                      GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
524                                      lsocks, loprefix, quotedbinary, "-L",
525                                      "DEBUG", options, NULL);
526       else
527         sl->proc =
528             GNUNET_OS_start_process_s (sl->pipe_control,
529                                        GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
530                                        lsocks, loprefix, quotedbinary, "-c",
531                                        sl->config, "-L",
532                                        "DEBUG", options, NULL);
533     }
534     else
535     {
536       if (NULL == sl->config)
537         sl->proc =
538             GNUNET_OS_start_process_s (sl->pipe_control,
539                                        GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
540                                        lsocks, loprefix, quotedbinary,
541                                        options, NULL);
542       else
543         sl->proc =
544             GNUNET_OS_start_process_s (sl->pipe_control,
545                                        GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
546                                        lsocks, loprefix, quotedbinary, "-c",
547                                        sl->config, options, NULL);
548     }
549   }
550   GNUNET_free (binary);
551   GNUNET_free (quotedbinary);
552   if (sl->proc == NULL)
553   {
554     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
555                 _("Failed to start service `%s'\n"),
556                 sl->name);
557     if (client)
558       signal_result (client,
559                      sl->name,
560                      request_id,
561                      GNUNET_ARM_RESULT_START_FAILED);
562   }
563   else
564   {
565     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
566                 _("Starting service `%s'\n"),
567                 sl->name);
568     broadcast_status (sl->name, GNUNET_ARM_SERVICE_STARTING, NULL);
569     if (client)
570       signal_result (client, sl->name, request_id, GNUNET_ARM_RESULT_STARTING);
571   }
572   /* clean up */
573   GNUNET_free (loprefix);
574   GNUNET_free (options);
575   GNUNET_array_grow (lsocks, ls, 0);
576 }
577
578
579 /**
580  * Find the process with the given service
581  * name in the given list and return it.
582  *
583  * @param name which service entry to look up
584  * @return NULL if it was not found
585  */
586 static struct ServiceList *
587 find_service (const char *name)
588 {
589   struct ServiceList *sl;
590
591   sl = running_head;
592   while (sl != NULL)
593     {
594       if (0 == strcasecmp (sl->name, name))
595         return sl;
596       sl = sl->next;
597     }
598   return NULL;
599 }
600
601
602 /**
603  * First connection has come to the listening socket associated with the service,
604  * create the service in order to relay the incoming connection to it
605  *
606  * @param cls callback data, `struct ServiceListeningInfo` describing a listen socket
607  */
608 static void
609 accept_connection (void *cls)
610 {
611   struct ServiceListeningInfo *sli = cls;
612   struct ServiceList *sl = sli->sl;
613
614   sli->accept_task = NULL;
615   GNUNET_assert (GNUNET_NO == in_shutdown);
616   start_process (sl, NULL, 0);
617 }
618
619
620 /**
621  * Creating a listening socket for each of the service's addresses and
622  * wait for the first incoming connection to it
623  *
624  * @param sa address associated with the service
625  * @param addr_len length of @a sa
626  * @param sl service entry for the service in question
627  */
628 static void
629 create_listen_socket (struct sockaddr *sa,
630                       socklen_t addr_len,
631                       struct ServiceList *sl)
632 {
633   static int on = 1;
634   struct GNUNET_NETWORK_Handle *sock;
635   struct ServiceListeningInfo *sli;
636 #ifndef WINDOWS
637   int match_uid;
638   int match_gid;
639 #endif
640
641   switch (sa->sa_family)
642   {
643   case AF_INET:
644     sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
645     break;
646   case AF_INET6:
647     sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
648     break;
649   case AF_UNIX:
650     if (strcmp (GNUNET_a2s (sa, addr_len), "@") == 0)   /* Do not bind to blank UNIX path! */
651       return;
652     sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
653     break;
654   default:
655     GNUNET_break (0);
656     sock = NULL;
657     errno = EAFNOSUPPORT;
658     break;
659   }
660   if (NULL == sock)
661   {
662     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
663                 _("Unable to create socket for service `%s': %s\n"),
664                 sl->name, STRERROR (errno));
665     GNUNET_free (sa);
666     return;
667   }
668   if (GNUNET_NETWORK_socket_setsockopt
669       (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
670     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
671                          "setsockopt");
672 #ifdef IPV6_V6ONLY
673   if ((sa->sa_family == AF_INET6) &&
674       (GNUNET_NETWORK_socket_setsockopt
675        (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK))
676     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
677                          "setsockopt");
678 #endif
679 #ifndef WINDOWS
680   if (AF_UNIX == sa->sa_family)
681     GNUNET_NETWORK_unix_precheck ((struct sockaddr_un *) sa);
682 #endif
683   if (GNUNET_OK !=
684       GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) sa, addr_len))
685   {
686     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
687                 _("Unable to bind listening socket for service `%s' to address `%s': %s\n"),
688                 sl->name,
689                 GNUNET_a2s (sa, addr_len),
690                 STRERROR (errno));
691     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
692     GNUNET_free (sa);
693     return;
694   }
695 #ifndef WINDOWS
696   if ((AF_UNIX == sa->sa_family)
697 #ifdef LINUX
698       /* Permission settings are not required when abstract sockets are used */
699       && ('\0' != ((const struct sockaddr_un *)sa)->sun_path[0])
700 #endif
701       )
702   {
703     match_uid =
704       GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name,
705                                             "UNIX_MATCH_UID");
706     match_gid =
707       GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name,
708                                             "UNIX_MATCH_GID");
709     GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sa)->sun_path,
710                                  match_uid,
711                                  match_gid);
712
713   }
714 #endif
715   if (GNUNET_NETWORK_socket_listen (sock, 5) != GNUNET_OK)
716   {
717     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
718     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
719     GNUNET_free (sa);
720     return;
721   }
722   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
723               _("ARM now monitors connections to service `%s' at `%s'\n"),
724               sl->name, GNUNET_a2s (sa, addr_len));
725   sli = GNUNET_new (struct ServiceListeningInfo);
726   sli->service_addr = sa;
727   sli->service_addr_len = addr_len;
728   sli->listen_socket = sock;
729   sli->sl = sl;
730   sli->accept_task =
731     GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sock,
732                                    &accept_connection, sli);
733   GNUNET_CONTAINER_DLL_insert (sl->listen_head,
734                                sl->listen_tail,
735                                sli);
736 }
737
738
739 /**
740  * Remove and free an entry in the service list.  Listen sockets
741  * must have already been cleaned up.  Only to be called during shutdown.
742  *
743  * @param sl entry to free
744  */
745 static void
746 free_service (struct ServiceList *sl)
747 {
748   GNUNET_assert (GNUNET_YES == in_shutdown);
749   GNUNET_CONTAINER_DLL_remove (running_head, running_tail, sl);
750   GNUNET_assert (NULL == sl->listen_head);
751   GNUNET_free_non_null (sl->config);
752   GNUNET_free_non_null (sl->binary);
753   GNUNET_free (sl->name);
754   GNUNET_free (sl);
755 }
756
757
758 /**
759  * Handle START-message.
760  *
761  * @param cls closure (always NULL)
762  * @param client identification of the client
763  * @param message the actual message
764  * @return #GNUNET_OK to keep the connection open,
765  *         #GNUNET_SYSERR to close it (signal serious error)
766  */
767 static void
768 handle_start (void *cls,
769               struct GNUNET_SERVER_Client *client,
770               const struct GNUNET_MessageHeader *message)
771 {
772   const char *servicename;
773   struct ServiceList *sl;
774   uint16_t size;
775   uint64_t request_id;
776   struct GNUNET_ARM_Message *amsg;
777
778   amsg = (struct GNUNET_ARM_Message *) message;
779   request_id = GNUNET_ntohll (amsg->request_id);
780   size = ntohs (amsg->header.size);
781   size -= sizeof (struct GNUNET_ARM_Message);
782   servicename = (const char *) &amsg[1];
783   if ((size == 0) || (servicename[size - 1] != '\0'))
784   {
785     GNUNET_break (0);
786     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
787     return;
788   }
789   if (GNUNET_YES == in_shutdown)
790   {
791     signal_result (client, servicename, request_id,
792                    GNUNET_ARM_RESULT_IN_SHUTDOWN);
793     GNUNET_SERVER_receive_done (client, GNUNET_OK);
794     return;
795   }
796   sl = find_service (servicename);
797   if (NULL == sl)
798   {
799     signal_result (client, servicename, request_id,
800                    GNUNET_ARM_RESULT_IS_NOT_KNOWN);
801     GNUNET_SERVER_receive_done (client, GNUNET_OK);
802     return;
803   }
804   sl->force_start = GNUNET_YES;
805   if (NULL != sl->proc)
806   {
807     signal_result (client, servicename, request_id,
808                    GNUNET_ARM_RESULT_IS_STARTED_ALREADY);
809     GNUNET_SERVER_receive_done (client, GNUNET_OK);
810     return;
811   }
812   start_process (sl, client, request_id);
813   GNUNET_SERVER_receive_done (client, GNUNET_OK);
814 }
815
816
817 /**
818  * Start a shutdown sequence.
819  *
820  * @param cls closure (refers to service)
821  */
822 static void
823 trigger_shutdown (void *cls)
824 {
825   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
826               "Triggering shutdown\n");
827   GNUNET_SCHEDULER_shutdown ();
828 }
829
830
831 /**
832  * Handle STOP-message.
833  *
834  * @param cls closure (always NULL)
835  * @param client identification of the client
836  * @param message the actual message
837  * @return #GNUNET_OK to keep the connection open,
838  *         #GNUNET_SYSERR to close it (signal serious error)
839  */
840 static void
841 handle_stop (void *cls,
842              struct GNUNET_SERVER_Client *client,
843              const struct GNUNET_MessageHeader *message)
844 {
845   struct ServiceList *sl;
846   const char *servicename;
847   uint16_t size;
848   uint64_t request_id;
849   struct GNUNET_ARM_Message *amsg;
850
851   amsg = (struct GNUNET_ARM_Message *) message;
852   request_id = GNUNET_ntohll (amsg->request_id);
853   size = ntohs (amsg->header.size);
854   size -= sizeof (struct GNUNET_ARM_Message);
855   servicename = (const char *) &amsg[1];
856   if ((size == 0) || (servicename[size - 1] != '\0'))
857     {
858       GNUNET_break (0);
859       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
860       return;
861     }
862   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
863               _("Preparing to stop `%s'\n"),
864               servicename);
865   if (0 == strcasecmp (servicename, "arm"))
866   {
867     broadcast_status (servicename,
868                       GNUNET_ARM_SERVICE_STOPPING, NULL);
869     signal_result (client,
870                    servicename,
871                    request_id,
872                    GNUNET_ARM_RESULT_STOPPING);
873     GNUNET_SERVER_client_persist_ (client);
874     GNUNET_SCHEDULER_add_now (&trigger_shutdown, NULL);
875     GNUNET_SERVER_receive_done (client, GNUNET_OK);
876     return;
877   }
878   sl = find_service (servicename);
879   if (sl == NULL)
880     {
881       signal_result (client,
882                      servicename,
883                      request_id,
884                      GNUNET_ARM_RESULT_IS_NOT_KNOWN);
885       GNUNET_SERVER_receive_done (client, GNUNET_OK);
886       return;
887     }
888   sl->force_start = GNUNET_NO;
889   if (GNUNET_YES == in_shutdown)
890     {
891       /* shutdown in progress */
892       signal_result (client,
893                      servicename,
894                      request_id,
895                      GNUNET_ARM_RESULT_IN_SHUTDOWN);
896       GNUNET_SERVER_receive_done (client, GNUNET_OK);
897       return;
898     }
899   if (NULL != sl->killing_client)
900   {
901     /* killing already in progress */
902     signal_result (client,
903                    servicename,
904                    request_id,
905                    GNUNET_ARM_RESULT_IS_STOPPING_ALREADY);
906     GNUNET_SERVER_receive_done (client, GNUNET_OK);
907     return;
908   }
909   if (NULL == sl->proc)
910   {
911     /* process is down */
912     signal_result (client,
913                    servicename,
914                    request_id,
915                    GNUNET_ARM_RESULT_IS_STOPPED_ALREADY);
916     GNUNET_SERVER_receive_done (client, GNUNET_OK);
917     return;
918   }
919   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
920               "Sending kill signal to service `%s', waiting for process to die.\n",
921               servicename);
922   broadcast_status (servicename,
923                     GNUNET_ARM_SERVICE_STOPPING,
924                     NULL);
925   /* no signal_start - only when it's STOPPED */
926   sl->killed_at = GNUNET_TIME_absolute_get ();
927   if (0 != GNUNET_OS_process_kill (sl->proc, GNUNET_TERM_SIG))
928     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
929   sl->killing_client = client;
930   sl->killing_client_request_id = request_id;
931   GNUNET_SERVER_client_keep (client);
932   GNUNET_SERVER_receive_done (client, GNUNET_OK);
933 }
934
935
936 /**
937  * Handle LIST-message.
938  *
939  * @param cls closure (always NULL)
940  * @param client identification of the client
941  * @param message the actual message
942  */
943 static void
944 handle_list (void *cls, struct GNUNET_SERVER_Client *client,
945              const struct GNUNET_MessageHeader *message)
946 {
947   struct GNUNET_ARM_ListResultMessage *msg;
948   struct GNUNET_ARM_Message *request;
949   size_t string_list_size;
950   size_t total_size;
951   struct ServiceList *sl;
952   uint16_t count;
953
954   if (NULL == client)
955     return;
956
957   request = (struct GNUNET_ARM_Message *) message;
958   GNUNET_break (0 == ntohl (request->reserved));
959   count = 0;
960   string_list_size = 0;
961   /* first count the running processes get their name's size */
962   for (sl = running_head; NULL != sl; sl = sl->next)
963   {
964     if (NULL != sl->proc)
965     {
966       string_list_size += strlen (sl->name);
967       string_list_size += strlen (sl->binary);
968       string_list_size += 4;
969       count++;
970     }
971   }
972
973   total_size = sizeof (struct GNUNET_ARM_ListResultMessage)
974                + string_list_size;
975   msg = GNUNET_malloc (total_size);
976   msg->arm_msg.header.size = total_size;
977   msg->arm_msg.header.type = GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT;
978   msg->arm_msg.reserved = htonl (0);
979   msg->arm_msg.request_id = GNUNET_ntohll (request->request_id);
980   msg->count = count;
981
982   char *pos = (char *)&msg[1];
983   for (sl = running_head; NULL != sl; sl = sl->next)
984   {
985     if (NULL != sl->proc)
986     {
987       size_t s = strlen (sl->name) + strlen (sl->binary) + 4;
988       GNUNET_snprintf (pos, s, "%s (%s)", sl->name, sl->binary);
989       pos += s;
990     }
991   }
992   GNUNET_SERVER_notify_transmit_ready (client,
993                                        total_size,
994                                        GNUNET_TIME_UNIT_FOREVER_REL,
995                                        &write_list_result, msg);
996   GNUNET_SERVER_receive_done (client, GNUNET_OK);
997 }
998
999
1000 /**
1001  * We are done with everything.  Stop remaining
1002  * tasks, signal handler and the server.
1003  */
1004 static void
1005 do_shutdown ()
1006 {
1007   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Last shutdown phase\n");
1008   if (NULL != notifier)
1009   {
1010     GNUNET_SERVER_notification_context_destroy (notifier);
1011     notifier = NULL;
1012   }
1013   if (NULL != server)
1014     {
1015       GNUNET_SERVER_destroy (server);
1016       server = NULL;
1017     }
1018   if (NULL != child_death_task)
1019     {
1020       GNUNET_SCHEDULER_cancel (child_death_task);
1021       child_death_task = NULL;
1022     }
1023 }
1024
1025
1026 /**
1027  * Count how many services are still active.
1028  *
1029  * @param running_head list of services
1030  * @return number of active services found
1031  */
1032 static unsigned int
1033 list_count (struct ServiceList *running_head)
1034 {
1035   struct ServiceList *i;
1036   unsigned int res = 0;
1037
1038   for (res = 0, i = running_head; i; i = i->next, res++)
1039     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1040                 "%s\n",
1041                 i->name);
1042   return res;
1043 }
1044
1045
1046 /**
1047  * Task run for shutdown.
1048  *
1049  * @param cls closure, NULL if we need to self-restart
1050  */
1051 static void
1052 shutdown_task (void *cls)
1053 {
1054   struct ServiceList *pos;
1055   struct ServiceList *nxt;
1056   struct ServiceListeningInfo *sli;
1057
1058   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1059               "First shutdown phase\n");
1060   if (NULL != child_restart_task)
1061   {
1062     GNUNET_SCHEDULER_cancel (child_restart_task);
1063     child_restart_task = NULL;
1064   }
1065   in_shutdown = GNUNET_YES;
1066   /* first, stop listening */
1067   for (pos = running_head; NULL != pos; pos = pos->next)
1068   {
1069     while (NULL != (sli = pos->listen_head))
1070       {
1071         GNUNET_CONTAINER_DLL_remove (pos->listen_head,
1072                                      pos->listen_tail,
1073                                      sli);
1074         if (NULL != sli->accept_task)
1075           {
1076             GNUNET_SCHEDULER_cancel (sli->accept_task);
1077             sli->accept_task = NULL;
1078           }
1079         GNUNET_break (GNUNET_OK ==
1080                       GNUNET_NETWORK_socket_close (sli->listen_socket));
1081         GNUNET_free (sli->service_addr);
1082         GNUNET_free (sli);
1083       }
1084   }
1085   /* then, shutdown all existing service processes */
1086   nxt = running_head;
1087   while (NULL != (pos = nxt))
1088   {
1089     nxt = pos->next;
1090     if (NULL != pos->proc)
1091     {
1092       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1093                   "Stopping service `%s'\n",
1094                   pos->name);
1095       pos->killed_at = GNUNET_TIME_absolute_get ();
1096       if (0 != GNUNET_OS_process_kill (pos->proc, GNUNET_TERM_SIG))
1097         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
1098     }
1099     else
1100     {
1101       free_service (pos);
1102     }
1103   }
1104   /* finally, should all service processes be already gone, terminate for real */
1105   if (NULL == running_head)
1106     do_shutdown ();
1107   else
1108     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1109                 "Delaying shutdown, have %u childs still running\n",
1110                 list_count (running_head));
1111 }
1112
1113
1114 /**
1115  * Task run whenever it is time to restart a child that died.
1116  *
1117  * @param cls closure, always NULL
1118  */
1119 static void
1120 delayed_restart_task (void *cls)
1121
1122 {
1123   struct ServiceList *sl;
1124   struct GNUNET_TIME_Relative lowestRestartDelay;
1125   struct ServiceListeningInfo *sli;
1126
1127   child_restart_task = NULL;
1128   GNUNET_assert (GNUNET_NO == in_shutdown);
1129   lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL;
1130
1131   /* check for services that need to be restarted due to
1132    * configuration changes or because the last restart failed */
1133   for (sl = running_head; NULL != sl; sl = sl->next)
1134   {
1135     if (NULL != sl->proc)
1136       continue;
1137     /* service is currently not running */
1138     if (0 == GNUNET_TIME_absolute_get_remaining (sl->restart_at).rel_value_us)
1139     {
1140       /* restart is now allowed */
1141       if (sl->force_start)
1142       {
1143         /* process should run by default, start immediately */
1144         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1145                     _("Restarting service `%s'.\n"),
1146                     sl->name);
1147         start_process (sl, NULL, 0);
1148       }
1149       else
1150       {
1151         /* process is run on-demand, ensure it is re-started if there is demand */
1152         for (sli = sl->listen_head; NULL != sli; sli = sli->next)
1153           if (NULL == sli->accept_task)
1154           {
1155             /* accept was actually paused, so start it again */
1156             sli->accept_task =
1157               GNUNET_SCHEDULER_add_read_net
1158               (GNUNET_TIME_UNIT_FOREVER_REL,
1159                sli->listen_socket,
1160                &accept_connection, sli);
1161           }
1162       }
1163     }
1164     else
1165     {
1166       /* update calculation for earliest time to reactivate a service */
1167       lowestRestartDelay =
1168         GNUNET_TIME_relative_min (lowestRestartDelay,
1169                                   GNUNET_TIME_absolute_get_remaining
1170                                   (sl->restart_at));
1171     }
1172   }
1173   if (lowestRestartDelay.rel_value_us != GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1174   {
1175     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1176                 "Will restart process in %s\n",
1177                 GNUNET_STRINGS_relative_time_to_string (lowestRestartDelay, GNUNET_YES));
1178     child_restart_task =
1179       GNUNET_SCHEDULER_add_delayed_with_priority (lowestRestartDelay,
1180                                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
1181                                                   &delayed_restart_task, NULL);
1182   }
1183 }
1184
1185
1186 /**
1187  * Task triggered whenever we receive a SIGCHLD (child
1188  * process died).
1189  *
1190  * @param cls closure, NULL if we need to self-restart
1191  */
1192 static void
1193 maint_child_death (void *cls)
1194 {
1195   struct ServiceList *pos;
1196   struct ServiceList *next;
1197   struct ServiceListeningInfo *sli;
1198   const char *statstr;
1199   int statcode;
1200   int ret;
1201   char c[16];
1202   enum GNUNET_OS_ProcessStatusType statusType;
1203   unsigned long statusCode;
1204   const struct GNUNET_DISK_FileHandle *pr;
1205
1206   pr = GNUNET_DISK_pipe_handle (sigpipe,
1207                                 GNUNET_DISK_PIPE_END_READ);
1208   child_death_task = NULL;
1209   /* consume the signal */
1210   GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
1211
1212   /* check for services that died (WAITPID) */
1213   next = running_head;
1214   while (NULL != (pos = next))
1215   {
1216     next = pos->next;
1217
1218     if (NULL == pos->proc)
1219     {
1220       if (GNUNET_YES == in_shutdown)
1221         free_service (pos);
1222       continue;
1223     }
1224 #if HAVE_WAIT4
1225     if (NULL != wait_file)
1226     {
1227       /* need to use 'wait4()' to obtain and log performance data */
1228       struct rusage ru;
1229       int status;
1230       pid_t pid;
1231
1232       pid = GNUNET_OS_process_get_pid (pos->proc);
1233       ret = wait4 (pid,
1234                    &status,
1235                    WNOHANG,
1236                    &ru);
1237       if (ret <= 0)
1238         continue; /* no process done */
1239       if (WIFEXITED (status))
1240       {
1241         statusType = GNUNET_OS_PROCESS_EXITED;
1242         statusCode = WEXITSTATUS (status);
1243       }
1244       else if (WIFSIGNALED (status))
1245       {
1246         statusType = GNUNET_OS_PROCESS_SIGNALED;
1247         statusCode = WTERMSIG (status);
1248       }
1249       else if (WIFSTOPPED (status))
1250       {
1251         statusType = GNUNET_OS_PROCESS_SIGNALED;
1252         statusCode = WSTOPSIG (status);
1253       }
1254 #ifdef WIFCONTINUED
1255       else if (WIFCONTINUED (status))
1256       {
1257         statusType = GNUNET_OS_PROCESS_RUNNING;
1258         statusCode = 0;
1259       }
1260 #endif
1261       else
1262       {
1263         statusType = GNUNET_OS_PROCESS_UNKNOWN;
1264         statusCode = 0;
1265       }
1266       if ( (GNUNET_OS_PROCESS_EXITED == statusType) ||
1267            (GNUNET_OS_PROCESS_SIGNALED == statusType) )
1268       {
1269         double utime = ru.ru_utime.tv_sec + (ru.ru_utime.tv_usec / 10e6);
1270         double stime = ru.ru_stime.tv_sec + (ru.ru_stime.tv_usec / 10e6);
1271         fprintf (wait_file,
1272                  "%s(%u) %.3f %.3f %llu %llu %llu %llu %llu\n",
1273                  pos->binary,
1274                  (unsigned int) pid,
1275                  utime,
1276                  stime,
1277                  (unsigned long long) ru.ru_maxrss,
1278                  (unsigned long long) ru.ru_inblock,
1279                  (unsigned long long) ru.ru_oublock,
1280                  (unsigned long long) ru.ru_nvcsw,
1281                  (unsigned long long) ru.ru_nivcsw);
1282       }
1283     }
1284     else /* continue with JUST this "if" as "else" (intentionally no brackets!) */
1285 #endif
1286     if ( (GNUNET_SYSERR ==
1287           (ret =
1288            GNUNET_OS_process_status (pos->proc,
1289                                      &statusType,
1290                                      &statusCode))) ||
1291          (ret == GNUNET_NO) ||
1292          (statusType == GNUNET_OS_PROCESS_STOPPED) ||
1293          (statusType == GNUNET_OS_PROCESS_UNKNOWN) ||
1294          (statusType == GNUNET_OS_PROCESS_RUNNING) )
1295       continue;
1296
1297     if (statusType == GNUNET_OS_PROCESS_EXITED)
1298     {
1299       statstr = _( /* process termination method */ "exit");
1300       statcode = statusCode;
1301     }
1302     else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
1303     {
1304       statstr = _( /* process termination method */ "signal");
1305       statcode = statusCode;
1306     }
1307     else
1308     {
1309       statstr = _( /* process termination method */ "unknown");
1310       statcode = 0;
1311     }
1312     if (0 != pos->killed_at.abs_value_us)
1313     {
1314       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1315                   _("Service `%s' took %s to terminate\n"),
1316                   pos->name,
1317                   GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->killed_at),
1318                                                           GNUNET_YES));
1319     }
1320     GNUNET_OS_process_destroy (pos->proc);
1321     pos->proc = NULL;
1322     broadcast_status (pos->name,
1323                       GNUNET_ARM_SERVICE_STOPPED,
1324                       NULL);
1325     if (NULL != pos->killing_client)
1326     {
1327       signal_result (pos->killing_client, pos->name,
1328                      pos->killing_client_request_id,
1329                      GNUNET_ARM_RESULT_STOPPED);
1330       GNUNET_SERVER_client_drop (pos->killing_client);
1331       pos->killing_client = NULL;
1332       pos->killing_client_request_id = 0;
1333     }
1334     if (GNUNET_YES != in_shutdown)
1335     {
1336       if ( (statusType == GNUNET_OS_PROCESS_EXITED) &&
1337            (statcode == 0) )
1338       {
1339         /* process terminated normally, allow restart at any time */
1340         pos->restart_at.abs_value_us = 0;
1341         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1342                     _("Service `%s' terminated normally, will restart at any time\n"),
1343                     pos->name);
1344         /* process can still be re-started on-demand, ensure it is re-started if there is demand */
1345         for (sli = pos->listen_head; NULL != sli; sli = sli->next)
1346         {
1347           GNUNET_break (NULL == sli->accept_task);
1348           sli->accept_task =
1349             GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1350                                            sli->listen_socket,
1351                                            &accept_connection,
1352                                            sli);
1353         }
1354       }
1355       else
1356       {
1357         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1358                     _("Service `%s' terminated with status %s/%d, will restart in %s\n"),
1359                     pos->name,
1360                     statstr,
1361                     statcode,
1362                     GNUNET_STRINGS_relative_time_to_string (pos->backoff,
1363                                                             GNUNET_YES));
1364         /* schedule restart */
1365         pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff);
1366         pos->backoff = GNUNET_TIME_STD_BACKOFF (pos->backoff);
1367         if (NULL != child_restart_task)
1368           GNUNET_SCHEDULER_cancel (child_restart_task);
1369         child_restart_task
1370           = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
1371                                                 &delayed_restart_task,
1372                                                 NULL);
1373       }
1374     }
1375     else
1376     {
1377       free_service (pos);
1378     }
1379   }
1380   child_death_task = GNUNET_SCHEDULER_add_read_file (
1381       GNUNET_TIME_UNIT_FOREVER_REL,
1382       pr,
1383       &maint_child_death, NULL);
1384   if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
1385     do_shutdown ();
1386   else if (GNUNET_YES == in_shutdown)
1387     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1388         "Delaying shutdown after child's death, still have %u children\n",
1389         list_count (running_head));
1390
1391 }
1392
1393
1394 /**
1395  * Signal handler called for SIGCHLD.  Triggers the
1396  * respective handler by writing to the trigger pipe.
1397  */
1398 static void
1399 sighandler_child_death ()
1400 {
1401   static char c;
1402   int old_errno = errno;        /* back-up errno */
1403
1404   GNUNET_break (1 ==
1405                 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
1406                                         (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
1407                                         &c, sizeof (c)));
1408   errno = old_errno;            /* restore errno */
1409 }
1410
1411
1412 /**
1413  * Setup our service record for the given section in the configuration file
1414  * (assuming the section is for a service).
1415  *
1416  * @param cls unused
1417  * @param section a section in the configuration file
1418  * @return #GNUNET_OK (continue)
1419  */
1420 static void
1421 setup_service (void *cls,
1422                const char *section)
1423 {
1424   struct ServiceList *sl;
1425   char *binary;
1426   char *config;
1427   struct stat sbuf;
1428   struct sockaddr **addrs;
1429   socklen_t *addr_lens;
1430   int ret;
1431   unsigned int i;
1432
1433   if (strcasecmp (section, "arm") == 0)
1434     return;
1435   if (GNUNET_OK !=
1436       GNUNET_CONFIGURATION_get_value_string (cfg, section, "BINARY", &binary))
1437   {
1438     /* not a service section */
1439     return;
1440   }
1441   if ((GNUNET_YES ==
1442        GNUNET_CONFIGURATION_have_value (cfg, section, "USER_SERVICE")) &&
1443       (GNUNET_YES ==
1444        GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "USER_SERVICE")))
1445   {
1446     if (GNUNET_NO == start_user)
1447     {
1448       GNUNET_free (binary);
1449       return; /* user service, and we don't deal with those */
1450     }
1451   }
1452   else
1453   {
1454     if (GNUNET_NO == start_system)
1455     {
1456       GNUNET_free (binary);
1457       return; /* system service, and we don't deal with those */
1458     }
1459   }
1460   sl = find_service (section);
1461   if (NULL != sl)
1462   {
1463     /* got the same section twice!? */
1464     GNUNET_break (0);
1465     GNUNET_free (binary);
1466     return;
1467   }
1468   config = NULL;
1469   if (( (GNUNET_OK !=
1470          GNUNET_CONFIGURATION_get_value_filename (cfg, section,
1471                                                   "CONFIG",
1472                                                   &config)) &&
1473         (GNUNET_OK !=
1474          GNUNET_CONFIGURATION_get_value_filename (cfg,
1475                                                   "PATHS",
1476                                                   "DEFAULTCONFIG",
1477                                                   &config)) ) ||
1478       (0 != STAT (config, &sbuf)))
1479   {
1480     if (NULL != config)
1481     {
1482       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1483                                  section, "CONFIG",
1484                                  STRERROR (errno));
1485       GNUNET_free (config);
1486       config = NULL;
1487     }
1488   }
1489   sl = GNUNET_new (struct ServiceList);
1490   sl->name = GNUNET_strdup (section);
1491   sl->binary = binary;
1492   sl->config = config;
1493   sl->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
1494   sl->restart_at = GNUNET_TIME_UNIT_FOREVER_ABS;
1495 #if WINDOWS
1496   sl->pipe_control = GNUNET_YES;
1497 #else
1498   if (GNUNET_CONFIGURATION_have_value (cfg, section, "PIPECONTROL"))
1499     sl->pipe_control = GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "PIPECONTROL");
1500 #endif
1501   GNUNET_CONTAINER_DLL_insert (running_head,
1502                                running_tail,
1503                                sl);
1504   if (GNUNET_YES ==
1505       GNUNET_CONFIGURATION_get_value_yesno (cfg,
1506                                             section,
1507                                             "FORCESTART"))
1508   {
1509     sl->force_start = GNUNET_YES;
1510     if (GNUNET_YES ==
1511         GNUNET_CONFIGURATION_get_value_yesno (cfg,
1512                                               section,
1513                                               "NOARMBIND"))
1514       return;
1515   }
1516   else
1517   {
1518     if (GNUNET_YES !=
1519         GNUNET_CONFIGURATION_get_value_yesno (cfg,
1520                                               section,
1521                                               "AUTOSTART"))
1522       return;
1523   }
1524   if (0 >= (ret = GNUNET_SERVICE_get_server_addresses (section,
1525                                                        cfg,
1526                                                        &addrs,
1527                                                        &addr_lens)))
1528     return;
1529   /* this will free (or capture) addrs[i] */
1530   for (i = 0; i < ret; i++)
1531     create_listen_socket (addrs[i],
1532                           addr_lens[i],
1533                           sl);
1534   GNUNET_free (addrs);
1535   GNUNET_free (addr_lens);
1536 }
1537
1538
1539 /**
1540  * A client connected, add it to the notification context.
1541  *
1542  * @param cls closure
1543  * @param client identification of the client
1544  */
1545 static void
1546 handle_client_connecting (void *cls, struct GNUNET_SERVER_Client *client)
1547 {
1548   /* All clients are considered to be of the "monitor" kind
1549    * (that is, they don't affect ARM shutdown).
1550    */
1551   if (NULL != client)
1552     GNUNET_SERVER_client_mark_monitor (client);
1553 }
1554
1555
1556 /**
1557  * Handle MONITOR-message.
1558  *
1559  * @param cls closure (always NULL)
1560  * @param client identification of the client
1561  * @param message the actual message
1562  * @return #GNUNET_OK to keep the connection open,
1563  *         #GNUNET_SYSERR to close it (signal serious error)
1564  */
1565 static void
1566 handle_monitor (void *cls, struct GNUNET_SERVER_Client *client,
1567              const struct GNUNET_MessageHeader *message)
1568 {
1569   /* Removal is handled by the server implementation, internally. */
1570   if ((NULL != client) && (NULL != notifier))
1571   {
1572     GNUNET_SERVER_notification_context_add (notifier, client);
1573     broadcast_status ("arm", GNUNET_ARM_SERVICE_MONITORING_STARTED, client);
1574     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1575   }
1576 }
1577
1578
1579 /**
1580  * Process arm requests.
1581  *
1582  * @param cls closure
1583  * @param serv the initialized server
1584  * @param c configuration to use
1585  */
1586 static void
1587 run (void *cls, struct GNUNET_SERVER_Handle *serv,
1588      const struct GNUNET_CONFIGURATION_Handle *c)
1589 {
1590   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1591     {&handle_start, NULL, GNUNET_MESSAGE_TYPE_ARM_START, 0},
1592     {&handle_stop, NULL, GNUNET_MESSAGE_TYPE_ARM_STOP, 0},
1593     {&handle_monitor, NULL, GNUNET_MESSAGE_TYPE_ARM_MONITOR,
1594      sizeof (struct GNUNET_MessageHeader)},
1595     {&handle_list, NULL, GNUNET_MESSAGE_TYPE_ARM_LIST,
1596      sizeof (struct GNUNET_ARM_Message)},
1597     {NULL, NULL, 0, 0}
1598   };
1599   struct ServiceList *sl;
1600
1601   cfg = c;
1602   server = serv;
1603   GNUNET_assert (NULL != serv);
1604   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1605                                  NULL);
1606   child_death_task =
1607     GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1608                                     GNUNET_DISK_pipe_handle (sigpipe,
1609                                                              GNUNET_DISK_PIPE_END_READ),
1610                                     &maint_child_death, NULL);
1611 #if HAVE_WAIT4
1612   if (GNUNET_OK ==
1613       GNUNET_CONFIGURATION_get_value_filename (cfg,
1614                                                "ARM",
1615                                                "RESOURCE_DIAGNOSTICS",
1616                                                &wait_filename))
1617   {
1618     wait_file = fopen (wait_filename,
1619                        "w");
1620     if (NULL == wait_file)
1621     {
1622       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1623                                 "fopen",
1624                                 wait_filename);
1625     }
1626   }
1627 #endif
1628   if (GNUNET_OK !=
1629       GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "GLOBAL_PREFIX",
1630                                              &prefix_command))
1631     prefix_command = GNUNET_strdup ("");
1632   if (GNUNET_OK !=
1633       GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "GLOBAL_POSTFIX",
1634                                              &final_option))
1635     final_option = GNUNET_strdup ("");
1636   if (GNUNET_YES ==
1637       GNUNET_CONFIGURATION_get_value_yesno (cfg, "ARM", "USER_ONLY"))
1638   {
1639     GNUNET_break (GNUNET_YES == start_user);
1640     start_system = GNUNET_NO;
1641   }
1642   if (GNUNET_YES ==
1643       GNUNET_CONFIGURATION_get_value_yesno (cfg, "ARM", "SYSTEM_ONLY"))
1644   {
1645     GNUNET_break (GNUNET_YES == start_system);
1646     start_user = GNUNET_NO;
1647   }
1648   GNUNET_CONFIGURATION_iterate_sections (cfg, &setup_service, NULL);
1649
1650   /* start default services... */
1651   for (sl = running_head; NULL != sl; sl = sl->next)
1652     if (GNUNET_YES == sl->force_start)
1653       start_process (sl, NULL, 0);
1654   notifier
1655     = GNUNET_SERVER_notification_context_create (server,
1656                                                  MAX_NOTIFY_QUEUE);
1657   GNUNET_SERVER_connect_notify (server,
1658                                 &handle_client_connecting, NULL);
1659   /* process client requests */
1660   GNUNET_SERVER_add_handlers (server,
1661                               handlers);
1662 }
1663
1664
1665 /**
1666  * The main function for the arm service.
1667  *
1668  * @param argc number of arguments from the command line
1669  * @param argv command line arguments
1670  * @return 0 ok, 1 on error
1671  */
1672 int
1673 main (int argc, char *const *argv)
1674 {
1675   int ret;
1676   struct GNUNET_SIGNAL_Context *shc_chld;
1677
1678   sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
1679   GNUNET_assert (sigpipe != NULL);
1680   shc_chld =
1681     GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
1682   ret =
1683     (GNUNET_OK ==
1684      GNUNET_SERVICE_run (argc, argv, "arm",
1685                          GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN, &run, NULL)) ? 0 : 1;
1686 #if HAVE_WAIT4
1687   if (NULL != wait_file)
1688   {
1689     fclose (wait_file);
1690     wait_file = NULL;
1691   }
1692   if (NULL != wait_filename)
1693   {
1694     GNUNET_free (wait_filename);
1695     wait_filename = NULL;
1696   }
1697 #endif
1698   GNUNET_SIGNAL_handler_uninstall (shc_chld);
1699   shc_chld = NULL;
1700   GNUNET_DISK_pipe_close (sigpipe);
1701   sigpipe = NULL;
1702   return ret;
1703 }
1704
1705
1706 #if defined(LINUX) && defined(__GLIBC__)
1707 #include <malloc.h>
1708
1709 /**
1710  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1711  */
1712 void __attribute__ ((constructor)) GNUNET_ARM_memory_init ()
1713 {
1714   mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1715   mallopt (M_TOP_PAD, 1 * 1024);
1716   malloc_trim (0);
1717 }
1718 #endif
1719
1720
1721 /* end of gnunet-service-arm.c */