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