2 This file is part of GNUnet.
3 (C) 2009, 2010 Christian Grothoff (and other contributing authors)
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 2, or (at your
8 option) any later version.
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.
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.
22 * @file arm/gnunet-service-arm.c
23 * @brief the automated restart manager service
24 * @author Christian Grothoff
27 * - need to test auto-restart code on configuration changes;
28 * - should refine restart code to check if *relevant* parts of the
29 * configuration were changed (anything in the section for the service)
30 * - should have a way to specify dependencies between services and
31 * manage restarts of groups of services
34 #include "gnunet_client_lib.h"
35 #include "gnunet_getopt_lib.h"
36 #include "gnunet_os_lib.h"
37 #include "gnunet_protocols.h"
38 #include "gnunet_service_lib.h"
39 #include "gnunet_signal_lib.h"
40 #include "gnunet-service-arm.h"
45 * Check for configuration file changes every 5s.
47 #define MAINT_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
50 * Threshold after which exponential backoff shouldn't increase (in ms); 30m
52 #define EXPONENTIAL_BACKOFF_THRESHOLD (1000 * 60 * 30)
54 #define DELAY_SHUTDOWN GNUNET_NO
57 * List of our services.
63 * List of our services.
68 * This is a linked list.
70 struct ServiceList *next;
73 * Name of the service.
78 * Name of the binary used.
83 * Name of the configuration file used.
88 * Client to notify upon kill completion (waitpid), NULL
89 * if we should simply restart the process.
91 struct GNUNET_SERVER_Client *killing_client;
94 * Process ID of the child.
99 * Last time the config of this service was
105 * Process exponential backoff time
107 struct GNUNET_TIME_Relative backoff;
110 * Absolute time at which the process is scheduled to restart in case of death
112 struct GNUNET_TIME_Absolute restartAt;
117 * List of running services.
119 static struct ServiceList *running;
124 static const struct GNUNET_CONFIGURATION_Handle *cfg;
129 static struct GNUNET_SCHEDULER_Handle *sched;
132 * Command to prepend to each actual command.
134 static char *prefix_command;
137 * Option to append to each actual command.
139 static char *final_option;
142 * ID of task called whenever we get a SIGCHILD.
144 static GNUNET_SCHEDULER_TaskIdentifier child_death_task;
147 * ID of task called whenever the timeout for restarting a child
150 static GNUNET_SCHEDULER_TaskIdentifier child_restart_task;
153 * Context for our SIGCHILD handler.
155 static struct GNUNET_SIGNAL_Context *shc_chld;
158 * Pipe used to communicate shutdown via signal.
160 static struct GNUNET_DISK_PipeHandle *sigpipe;
163 * Reading end of the signal pipe.
165 static const struct GNUNET_DISK_FileHandle *pr;
168 * Are we in shutdown mode?
170 static int in_shutdown;
174 * Handle to our server instance. Our server is a bit special in that
175 * its service is not immediately stopped once we get a shutdown
176 * request (since we need to continue service until all of our child
177 * processes are dead). This handle is used to shut down the server
178 * (and thus trigger process termination) once all child processes are
179 * also dead. A special option in the ARM configuration modifies the
180 * behaviour of the service implementation to not do the shutdown
183 static struct GNUNET_SERVER_Handle *server;
187 * If the configuration file changes, restart tasks that depended on that
190 * @param cls closure, NULL if we need to self-restart
194 config_change_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
196 struct ServiceList *pos;
202 /* FIXME: this test for config change is a bit too coarse grained */
203 if ( (0 == STAT (pos->config, &sbuf)) &&
204 (pos->mtime < sbuf.st_mtime) &&
207 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
208 _("Restarting service `%s' due to configuration file change.\n"));
209 if (0 != PLIBC_KILL (pos->pid, SIGTERM))
210 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
212 pos->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
221 * Transmit a status result message.
223 * @param cls pointer to "unit16_t*" with message type
224 * @param size number of bytes available in buf
225 * @param buf where to copy the message, NULL on error
226 * @return number of bytes copied to buf
229 write_result (void *cls, size_t size, void *buf)
232 struct GNUNET_MessageHeader *msg;
236 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
237 _("Could not send status result to client\n"));
238 return 0; /* error, not much we can do */
241 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
242 "Sending status response %u to client\n",
243 (unsigned int) *res);
245 GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
247 msg->size = htons (sizeof (struct GNUNET_MessageHeader));
248 msg->type = htons (*res);
250 return sizeof (struct GNUNET_MessageHeader);
256 * Signal our client that we will start or stop the
259 * @param client who is being signalled
260 * @param name name of the service
261 * @param result message type to send
262 * @return NULL if it was not found
265 signal_result (struct GNUNET_SERVER_Client *client,
266 const char *name, uint16_t result)
272 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
274 ("Not sending status result to client: no client known\n"));
278 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
279 "Telling client that service `%s' is now %s\n",
281 result == GNUNET_MESSAGE_TYPE_ARM_IS_DOWN ? "down" : "up");
283 res = GNUNET_malloc (sizeof (uint16_t));
285 GNUNET_SERVER_notify_transmit_ready (client,
286 sizeof (struct GNUNET_MessageHeader),
287 GNUNET_TIME_UNIT_FOREVER_REL,
293 * Find the process with the given service
294 * name in the given list, remove it and return it.
296 * @param name which service entry to look up
297 * @return NULL if it was not found
299 static struct ServiceList *
300 find_name (const char *name)
302 struct ServiceList *pos;
303 struct ServiceList *prev;
309 if (0 == strcmp (pos->name, name))
314 prev->next = pos->next;
326 * Free an entry in the service list.
328 * @param pos entry to free
331 free_entry (struct ServiceList *pos)
333 GNUNET_free_non_null (pos->config);
334 GNUNET_free_non_null (pos->binary);
335 GNUNET_free (pos->name);
339 #include "do_start_process.c"
342 * Actually start the process for the given service.
344 * @param sl identifies service to start
347 start_process (struct ServiceList *sl)
360 GNUNET_CONFIGURATION_get_value_string (cfg,
361 sl->name, "PREFIX", &loprefix))
362 loprefix = GNUNET_strdup (prefix_command);
364 GNUNET_CONFIGURATION_get_value_string (cfg,
365 sl->name, "OPTIONS", &options))
367 options = GNUNET_strdup (final_option);
368 if (NULL == strstr (options, "%"))
370 /* replace '{}' with service name */
371 while (NULL != (optpos = strstr (options, "{}")))
375 GNUNET_asprintf (&optpos,
378 GNUNET_free (options);
381 /* replace '$PATH' with value associated with "PATH" */
382 while (NULL != (optpos = strstr (options, "$")))
385 while (isupper ( (unsigned char) *optend)) optend++;
393 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
396 val = GNUNET_strdup ("");
398 GNUNET_asprintf (&optpos,
404 GNUNET_free (options);
410 use_debug = GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name, "DEBUG");
413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
414 "Starting service `%s' using binary `%s' and configuration `%s'\n",
415 sl->name, sl->binary, sl->config);
417 if (GNUNET_YES == use_debug)
418 sl->pid = do_start_process (loprefix,
425 sl->pid = do_start_process (loprefix,
430 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
431 _("Starting service `%s' (PID: %d)\n"),
434 GNUNET_free (loprefix);
435 GNUNET_free (options);
436 /* FIXME: should check sl->pid */
441 * Start the specified service.
443 * @param client who is asking for this
444 * @param servicename name of the service to start
447 start_service (struct GNUNET_SERVER_Client *client, const char *servicename)
449 struct ServiceList *sl;
454 if (GNUNET_YES == in_shutdown)
456 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
457 _("ARM is shutting down, service `%s' not started.\n"),
459 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
462 sl = find_name (servicename);
465 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
466 _("Service `%s' already running.\n"), servicename);
469 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_UP);
473 GNUNET_CONFIGURATION_get_value_string (cfg,
474 servicename, "BINARY", &binary))
476 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
477 _("Binary implementing service `%s' not known!\n"),
479 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
483 GNUNET_CONFIGURATION_get_value_filename (cfg,
487 (0 != STAT (config, &sbuf)))
489 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
490 _("Configuration file `%s' for service `%s' not known!\n"),
491 config, servicename);
492 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
493 GNUNET_free (binary);
494 GNUNET_free_non_null (config);
497 (void) stop_listening (servicename);
498 sl = GNUNET_malloc (sizeof (struct ServiceList));
499 sl->name = GNUNET_strdup (servicename);
503 sl->mtime = sbuf.st_mtime;
504 sl->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
505 sl->restartAt = GNUNET_TIME_UNIT_FOREVER_ABS;
510 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_UP);
515 * Stop the specified service.
517 * @param client who is asking for this
518 * @param servicename name of the service to stop
521 stop_service (struct GNUNET_SERVER_Client *client,
522 const char *servicename)
524 struct ServiceList *pos;
526 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
527 _("Preparing to stop `%s'\n"), servicename);
528 pos = find_name (servicename);
531 if (GNUNET_OK == stop_listening (servicename))
532 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
534 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_UNKNOWN);
535 GNUNET_SERVER_receive_done (client, GNUNET_OK);
538 if (pos->killing_client != NULL)
540 /* killing already in progress */
542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
543 "Service `%s' is already down\n", servicename);
545 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
546 GNUNET_SERVER_receive_done (client, GNUNET_OK);
552 if (GNUNET_YES == in_shutdown)
555 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
556 "Termination request already sent to `%s' (since ARM is in shutdown).\n",
559 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
560 GNUNET_SERVER_receive_done (client, GNUNET_OK);
567 /* process is in delayed restart, simply remove it! */
569 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
570 GNUNET_SERVER_receive_done (client, GNUNET_OK);
574 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
575 "Sending kill signal to service `%s', waiting for process to die.\n",
578 if (0 != PLIBC_KILL (pos->pid, SIGTERM))
579 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
582 pos->killing_client = client;
583 GNUNET_SERVER_client_keep (client);
588 * Handle START-message.
590 * @param cls closure (always NULL)
591 * @param client identification of the client
592 * @param message the actual message
593 * @return GNUNET_OK to keep the connection open,
594 * GNUNET_SYSERR to close it (signal serious error)
597 handle_start (void *cls,
598 struct GNUNET_SERVER_Client *client,
599 const struct GNUNET_MessageHeader *message)
601 const char *servicename;
604 size = ntohs (message->size);
605 size -= sizeof (struct GNUNET_MessageHeader);
606 servicename = (const char *) &message[1];
607 if ((size == 0) || (servicename[size - 1] != '\0'))
610 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
613 start_service (client, servicename);
614 GNUNET_SERVER_receive_done (client, GNUNET_OK);
619 * Handle STOP-message.
621 * @param cls closure (always NULL)
622 * @param client identification of the client
623 * @param message the actual message
624 * @return GNUNET_OK to keep the connection open,
625 * GNUNET_SYSERR to close it (signal serious error)
628 handle_stop (void *cls,
629 struct GNUNET_SERVER_Client *client,
630 const struct GNUNET_MessageHeader *message)
632 const char *servicename;
635 size = ntohs (message->size);
636 size -= sizeof (struct GNUNET_MessageHeader);
637 servicename = (const char *) &message[1];
638 if ((size == 0) || (servicename[size - 1] != '\0'))
641 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
644 stop_service (client, servicename);
649 * Remove all entries for tasks that are not running
650 * (pid = 0) from the running list (they will no longer
651 * be restarted since we are shutting down).
656 struct ServiceList *pos;
657 struct ServiceList *next;
658 struct ServiceList *prev;
681 * We are done with everything. Stop remaining
682 * tasks, signal handler and the server.
687 GNUNET_SERVER_destroy (server);
689 GNUNET_SIGNAL_handler_uninstall (shc_chld);
691 GNUNET_SCHEDULER_cancel (sched, child_death_task);
692 child_death_task = GNUNET_SCHEDULER_NO_TASK;
697 * Dummy task to delay arm shutdown.
699 void dummy_task (void *cls,
700 const struct GNUNET_SCHEDULER_TaskContext * tc)
702 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Dummy task executing\n");
708 * Task run for shutdown.
710 * @param cls closure, NULL if we need to self-restart
714 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
716 struct ServiceList *pos;
719 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Stopping all services\n"));
721 stop_listening (NULL);
722 in_shutdown = GNUNET_YES;
728 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
729 "Stopping service `%s' (PID: %d)\n",
732 if (0 != PLIBC_KILL (pos->pid, SIGTERM))
733 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
738 GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 2), &dummy_task, NULL);
746 * Task run whenever it is time to restart a child that died.
748 * @param cls closure, always NULL
752 delayed_restart_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
754 struct ServiceList *pos;
755 struct GNUNET_TIME_Relative lowestRestartDelay;
757 child_restart_task = GNUNET_SCHEDULER_NO_TASK;
758 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
765 lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL;
767 /* check for services that need to be restarted due to
768 configuration changes or because the last restart failed */
772 if ( (pos->pid == 0) &&
773 (GNUNET_YES != in_shutdown) )
775 if (GNUNET_TIME_absolute_get_remaining (pos->restartAt).value == 0)
777 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
778 _("Restarting service `%s'.\n"), pos->name);
784 = GNUNET_TIME_relative_min (lowestRestartDelay,
785 GNUNET_TIME_absolute_get_remaining
791 if (lowestRestartDelay.value != GNUNET_TIME_UNIT_FOREVER_REL.value)
794 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
795 "Will restart process in %llums\n",
796 (unsigned long long) lowestRestartDelay.value);
799 = GNUNET_SCHEDULER_add_delayed (sched,
801 &delayed_restart_task,
808 * Task triggered whenever we receive a SIGCHLD (child
811 * @param cls closure, NULL if we need to self-restart
815 maint_child_death (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
817 struct ServiceList *pos;
818 struct ServiceList *prev;
819 struct ServiceList *next;
824 enum GNUNET_OS_ProcessStatusType statusType;
825 unsigned long statusCode;
827 child_death_task = GNUNET_SCHEDULER_NO_TASK;
828 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
831 GNUNET_SCHEDULER_add_read_file (sched, GNUNET_TIME_UNIT_FOREVER_REL, pr,
832 &maint_child_death, NULL);
835 /* consume the signal */
836 GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
838 /* check for services that died (WAITPID) */
841 while (NULL != (pos = next))
849 if ((GNUNET_SYSERR == (ret = GNUNET_OS_process_status (pos->pid,
852 ( (ret == GNUNET_NO) ||
853 (statusType == GNUNET_OS_PROCESS_STOPPED) ||
854 (statusType == GNUNET_OS_PROCESS_RUNNING)) )
860 if (statusType == GNUNET_OS_PROCESS_EXITED)
862 statstr = _( /* process termination method */ "exit");
863 statcode = statusCode;
865 else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
867 statstr = _( /* process termination method */ "signal");
868 statcode = statusCode;
872 statstr = _( /* process termination method */ "unknown");
876 if (NULL != pos->killing_client)
882 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
883 _("Service `%s' stopped\n"),
885 signal_result (pos->killing_client,
886 pos->name, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
887 GNUNET_SERVER_receive_done (pos->killing_client, GNUNET_OK);
888 GNUNET_SERVER_client_drop (pos->killing_client);
892 if (GNUNET_YES != in_shutdown)
894 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
896 ("Service `%s' terminated with status %s/%d, will try to restart it!\n"),
897 pos->name, statstr, statcode);
898 /* schedule restart */
900 = GNUNET_TIME_relative_to_absolute (pos->backoff);
901 if (pos->backoff.value < EXPONENTIAL_BACKOFF_THRESHOLD)
903 = GNUNET_TIME_relative_multiply (pos->backoff, 2);
904 if (GNUNET_SCHEDULER_NO_TASK != child_restart_task)
905 GNUNET_SCHEDULER_cancel (sched, child_restart_task);
907 = GNUNET_SCHEDULER_add_with_priority (sched,
908 GNUNET_SCHEDULER_PRIORITY_IDLE,
909 &delayed_restart_task,
914 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
915 "Service `%s' terminated with status %s/%d\n",
916 pos->name, statstr, statcode);
922 if ( (running == NULL) &&
925 GNUNET_SERVER_destroy (server);
926 GNUNET_SIGNAL_handler_uninstall (shc_chld);
932 GNUNET_SCHEDULER_add_read_file (sched, GNUNET_TIME_UNIT_FOREVER_REL, pr,
933 &maint_child_death, NULL);
939 transmit_shutdown_ack (void *cls, size_t size, void *buf)
941 struct GNUNET_SERVER_Client *client = cls;
942 struct GNUNET_MessageHeader *msg;
944 if (size < sizeof (struct GNUNET_MessageHeader))
946 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
947 _("Failed to transmit shutdown ACK.\n"));
948 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
949 return 0; /* client disconnected */
952 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
953 _("Transmitting shutdown ACK.\n"));
955 msg = (struct GNUNET_MessageHeader *) buf;
956 msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN_ACK);
957 msg->size = htons (sizeof (struct GNUNET_MessageHeader));
958 GNUNET_SERVER_receive_done (client, GNUNET_OK);
959 GNUNET_SERVER_client_drop(client);
960 return sizeof (struct GNUNET_MessageHeader);
964 * Handler for SHUTDOWN message.
966 * @param cls closure (refers to service)
967 * @param client identification of the client
968 * @param message the actual message
971 handle_shutdown (void *cls,
972 struct GNUNET_SERVER_Client *client,
973 const struct GNUNET_MessageHeader *message)
975 GNUNET_SERVER_client_keep(client);
976 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
977 _("Initiating shutdown as requested by client.\n"));
979 GNUNET_SERVER_notify_transmit_ready (client,
980 sizeof(struct GNUNET_MessageHeader),
981 GNUNET_TIME_UNIT_FOREVER_REL,
982 &transmit_shutdown_ack, client);
983 GNUNET_SERVER_client_persist_ (client);
984 GNUNET_SCHEDULER_shutdown (sched);
989 * Signal handler called for SIGCHLD. Triggers the
990 * respective handler by writing to the trigger pipe.
993 sighandler_child_death ()
997 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
998 (sigpipe, GNUNET_DISK_PIPE_END_WRITE), &c,
1004 * Process arm requests.
1006 * @param cls closure
1007 * @param s scheduler to use
1008 * @param serv the initialized server
1009 * @param c configuration to use
1013 struct GNUNET_SCHEDULER_Handle *s,
1014 struct GNUNET_SERVER_Handle *serv,
1015 const struct GNUNET_CONFIGURATION_Handle *c)
1017 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1018 {&handle_start, NULL, GNUNET_MESSAGE_TYPE_ARM_START, 0},
1019 {&handle_stop, NULL, GNUNET_MESSAGE_TYPE_ARM_STOP, 0},
1020 {&handle_shutdown, NULL, GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN,
1021 sizeof (struct GNUNET_MessageHeader)},
1024 char *defaultservices;
1030 GNUNET_assert (serv != NULL);
1031 shc_chld = GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
1032 GNUNET_assert (sigpipe == NULL);
1033 sigpipe = GNUNET_DISK_pipe (GNUNET_NO);
1034 GNUNET_assert (sigpipe != NULL);
1035 pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
1036 GNUNET_assert (pr != NULL);
1037 GNUNET_SERVER_ignore_shutdown (serv, GNUNET_YES);
1038 GNUNET_SCHEDULER_add_delayed (sched,
1039 GNUNET_TIME_UNIT_FOREVER_REL,
1043 GNUNET_SCHEDULER_add_read_file (sched, GNUNET_TIME_UNIT_FOREVER_REL, pr,
1044 &maint_child_death, NULL);
1047 GNUNET_CONFIGURATION_get_value_string (cfg,
1051 prefix_command = GNUNET_strdup ("");
1053 GNUNET_CONFIGURATION_get_value_string (cfg,
1057 final_option = GNUNET_strdup ("");
1058 /* start default services... */
1060 GNUNET_CONFIGURATION_get_value_string (cfg,
1066 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1067 "Starting default services `%s'\n", defaultservices);
1069 if (0 < strlen (defaultservices))
1071 pos = strtok (defaultservices, " ");
1074 start_service (NULL, pos);
1075 pos = strtok (NULL, " ");
1078 GNUNET_free (defaultservices);
1083 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1084 "No default services configured.\n");
1088 /* create listening sockets for future services*/
1089 prepareServices (cfg, sched);
1091 /* process client requests */
1092 GNUNET_SERVER_add_handlers (server, handlers);
1094 /* manage services */
1095 GNUNET_SCHEDULER_add_with_priority (sched,
1096 GNUNET_SCHEDULER_PRIORITY_IDLE,
1097 &config_change_task, NULL);
1102 * The main function for the arm service.
1104 * @param argc number of arguments from the command line
1105 * @param argv command line arguments
1106 * @return 0 ok, 1 on error
1109 main (int argc, char *const *argv)
1111 return (GNUNET_OK ==
1112 GNUNET_SERVICE_run (argc,
1113 argv, "arm", GNUNET_YES, &run, NULL)) ? 0 : 1;
1116 /* end of gnunet-service-arm.c */