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