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