aboutsummaryrefslogtreecommitdiff
path: root/src/arm/gnunet-service-arm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/arm/gnunet-service-arm.c')
-rw-r--r--src/arm/gnunet-service-arm.c1466
1 files changed, 630 insertions, 836 deletions
diff --git a/src/arm/gnunet-service-arm.c b/src/arm/gnunet-service-arm.c
index 74bbd76c2..733eac6c6 100644
--- a/src/arm/gnunet-service-arm.c
+++ b/src/arm/gnunet-service-arm.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 (C) 2009, 2010 Christian Grothoff (and other contributing authors) 3 (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 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 6 it under the terms of the GNU General Public License as published
@@ -22,31 +22,18 @@
22 * @file arm/gnunet-service-arm.c 22 * @file arm/gnunet-service-arm.c
23 * @brief the automated restart manager service 23 * @brief the automated restart manager service
24 * @author Christian Grothoff 24 * @author Christian Grothoff
25 *
26 * TODO:
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
32 *
33 * + install handler for disconnecting clients!?
34 */ 25 */
35#include "platform.h" 26#include "platform.h"
36#include "gnunet_util_lib.h" 27#include "gnunet_util_lib.h"
28#include "gnunet_arm_service.h"
37#include "gnunet_protocols.h" 29#include "gnunet_protocols.h"
38#include "arm.h" 30#include "arm.h"
39 31
40
41/**
42 * Check for configuration file changes every 5s.
43 */
44#define MAINT_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
45
46/** 32/**
47 * Threshold after which exponential backoff shouldn't increase (in ms); 30m 33 * Threshold after which exponential backoff shouldn't increase (in ms); 30m
48 */ 34 */
49#define EXPONENTIAL_BACKOFF_THRESHOLD (1000 * 60 * 30) 35#define EXPONENTIAL_BACKOFF_THRESHOLD GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
36
50 37
51/** 38/**
52 * List of our services. 39 * List of our services.
@@ -55,6 +42,49 @@ struct ServiceList;
55 42
56 43
57/** 44/**
45 * Record with information about a listen socket we have open.
46 */
47struct ServiceListeningInfo
48{
49 /**
50 * This is a linked list.
51 */
52 struct ServiceListeningInfo *next;
53
54 /**
55 * This is a linked list.
56 */
57 struct ServiceListeningInfo *prev;
58
59 /**
60 * Address this socket is listening on.
61 */
62 struct sockaddr *service_addr;
63
64 /**
65 * Service this listen socket is for.
66 */
67 struct ServiceList *sl;
68
69 /**
70 * Number of bytes in 'service_addr'
71 */
72 socklen_t service_addr_len;
73
74 /**
75 * Our listening socket.
76 */
77 struct GNUNET_NETWORK_Handle *listen_socket;
78
79 /**
80 * Task doing the accepting.
81 */
82 GNUNET_SCHEDULER_TaskIdentifier accept_task;
83
84};
85
86
87/**
58 * List of our services. 88 * List of our services.
59 */ 89 */
60struct ServiceList 90struct ServiceList
@@ -70,6 +100,16 @@ struct ServiceList
70 struct ServiceList *prev; 100 struct ServiceList *prev;
71 101
72 /** 102 /**
103 * Linked list of listen sockets associated with this service.
104 */
105 struct ServiceListeningInfo *listen_head;
106
107 /**
108 * Linked list of listen sockets associated with this service.
109 */
110 struct ServiceListeningInfo *listen_tail;
111
112 /**
73 * Name of the service. 113 * Name of the service.
74 */ 114 */
75 char *name; 115 char *name;
@@ -96,12 +136,6 @@ struct ServiceList
96 struct GNUNET_OS_Process *proc; 136 struct GNUNET_OS_Process *proc;
97 137
98 /** 138 /**
99 * Last time the config of this service was
100 * modified.
101 */
102 time_t mtime;
103
104 /**
105 * Process exponential backoff time 139 * Process exponential backoff time
106 */ 140 */
107 struct GNUNET_TIME_Relative backoff; 141 struct GNUNET_TIME_Relative backoff;
@@ -109,7 +143,14 @@ struct ServiceList
109 /** 143 /**
110 * Absolute time at which the process is scheduled to restart in case of death 144 * Absolute time at which the process is scheduled to restart in case of death
111 */ 145 */
112 struct GNUNET_TIME_Absolute restartAt; 146 struct GNUNET_TIME_Absolute restart_at;
147
148 /**
149 * Is this service to be started by default (or did a client tell us explicitly
150 * to start it)? GNUNET_NO if the service is started only upon 'accept' on a
151 * listen socket or possibly explicitly by a client changing the value.
152 */
153 int is_default;
113 154
114}; 155};
115 156
@@ -150,84 +191,15 @@ static GNUNET_SCHEDULER_TaskIdentifier child_death_task;
150static GNUNET_SCHEDULER_TaskIdentifier child_restart_task; 191static GNUNET_SCHEDULER_TaskIdentifier child_restart_task;
151 192
152/** 193/**
153 *
154 */
155struct ServiceListeningInfo
156{
157 /**
158 * This is a linked list.
159 */
160 struct ServiceListeningInfo *next;
161
162 /**
163 * This is a linked list.
164 */
165 struct ServiceListeningInfo *prev;
166
167 /**
168 * Name of the service being forwarded.
169 */
170 char *serviceName;
171
172 /**
173 *
174 */
175 struct sockaddr *service_addr;
176
177 /**
178 *
179 */
180 socklen_t service_addr_len;
181
182 /**
183 * Our listening socket.
184 */
185 struct GNUNET_NETWORK_Handle *listeningSocket;
186
187 /**
188 * Task doing the accepting.
189 */
190 GNUNET_SCHEDULER_TaskIdentifier acceptTask;
191};
192
193
194/**
195 * Array with the names of the services started by default.
196 */
197static char **defaultServicesList;
198
199/**
200 * Size of the defaultServicesList array.
201 */
202static unsigned int numDefaultServices;
203
204/**
205 *
206 */
207static struct ServiceListeningInfo *serviceListeningInfoList_head;
208
209/**
210 *
211 */
212static struct ServiceListeningInfo *serviceListeningInfoList_tail;
213
214
215/**
216 * Pipe used to communicate shutdown via signal. 194 * Pipe used to communicate shutdown via signal.
217 */ 195 */
218static struct GNUNET_DISK_PipeHandle *sigpipe; 196static struct GNUNET_DISK_PipeHandle *sigpipe;
219 197
220/** 198/**
221 * Reading end of the signal pipe.
222 */
223static const struct GNUNET_DISK_FileHandle *pr;
224
225/**
226 * Are we in shutdown mode? 199 * Are we in shutdown mode?
227 */ 200 */
228static int in_shutdown; 201static int in_shutdown;
229 202
230
231/** 203/**
232 * Handle to our server instance. Our server is a bit special in that 204 * Handle to our server instance. Our server is a bit special in that
233 * its service is not immediately stopped once we get a shutdown 205 * its service is not immediately stopped once we get a shutdown
@@ -248,10 +220,9 @@ static struct GNUNET_SERVER_Handle *server;
248 * Actually start the process for the given service. 220 * Actually start the process for the given service.
249 * 221 *
250 * @param sl identifies service to start 222 * @param sl identifies service to start
251 * @param lsocks -1 terminated list of listen sockets to pass (systemd style), or NULL
252 */ 223 */
253static void 224static void
254start_process (struct ServiceList *sl, const SOCKTYPE *lsocks) 225start_process (struct ServiceList *sl)
255{ 226{
256 char *loprefix; 227 char *loprefix;
257 char *options; 228 char *options;
@@ -261,161 +232,100 @@ start_process (struct ServiceList *sl, const SOCKTYPE *lsocks)
261 int use_debug; 232 int use_debug;
262 char b; 233 char b;
263 char *val; 234 char *val;
235 struct ServiceListeningInfo *sli;
236 SOCKTYPE *lsocks;
237 unsigned int ls;
238
239 /* calculate listen socket list */
240 lsocks = NULL;
241 ls = 0;
242 for (sli = sl->listen_head; NULL != sli; sli = sli->next)
243 {
244 GNUNET_array_append (lsocks, ls,
245 GNUNET_NETWORK_get_fd (sli->listen_socket));
246 if (sli->accept_task != GNUNET_SCHEDULER_NO_TASK)
247 {
248 GNUNET_SCHEDULER_cancel (sli->accept_task);
249 sli->accept_task = GNUNET_SCHEDULER_NO_TASK;
250 }
251 }
252#if WINDOWS
253 GNUNET_array_append (lsocks, ls, INVALID_SOCKET);
254#else
255 GNUNET_array_append (lsocks, ls, -1);
256#endif
264 257
265 /* start service */ 258 /* obtain configuration */
266 if (GNUNET_OK != 259 if (GNUNET_OK !=
267 GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "PREFIX", 260 GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "PREFIX",
268 &loprefix)) 261 &loprefix))
269 loprefix = GNUNET_strdup (prefix_command); 262 loprefix = GNUNET_strdup (prefix_command);
270 if (GNUNET_OK != 263 if (GNUNET_OK !=
271 GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "OPTIONS", 264 GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "OPTIONS",
272 &options)) 265 &options))
273 {
274 options = GNUNET_strdup (final_option);
275 if (NULL == strstr (options, "%"))
276 { 266 {
277 /* replace '{}' with service name */ 267 options = GNUNET_strdup (final_option);
278 while (NULL != (optpos = strstr (options, "{}"))) 268 if (NULL == strstr (options, "%"))
279 { 269 {
280 optpos[0] = '%'; 270 /* replace '{}' with service name */
281 optpos[1] = 's'; 271 while (NULL != (optpos = strstr (options, "{}")))
282 GNUNET_asprintf (&optpos, options, sl->name); 272 {
283 GNUNET_free (options); 273 optpos[0] = '%';
284 options = optpos; 274 optpos[1] = 's';
285 } 275 GNUNET_asprintf (&optpos, options, sl->name);
286 /* replace '$PATH' with value associated with "PATH" */ 276 GNUNET_free (options);
287 while (NULL != (optpos = strstr (options, "$"))) 277 options = optpos;
288 { 278 }
289 optend = optpos + 1; 279 /* replace '$PATH' with value associated with "PATH" */
290 while (isupper ((unsigned char) *optend)) 280 while (NULL != (optpos = strstr (options, "$")))
291 optend++; 281 {
292 b = *optend; 282 optend = optpos + 1;
293 if ('\0' == b) 283 while (isupper ((unsigned char) *optend))
294 next = ""; 284 optend++;
295 else 285 b = *optend;
296 next = optend + 1; 286 if ('\0' == b)
297 *optend = '\0'; 287 next = "";
298 if (GNUNET_OK != 288 else
299 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", optpos + 1, 289 next = optend + 1;
300 &val)) 290 *optend = '\0';
301 val = GNUNET_strdup (""); 291 if (GNUNET_OK !=
302 *optpos = '\0'; 292 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
303 GNUNET_asprintf (&optpos, "%s%s%c%s", options, val, b, next); 293 optpos + 1, &val))
304 GNUNET_free (options); 294 val = GNUNET_strdup ("");
305 GNUNET_free (val); 295 *optpos = '\0';
306 options = optpos; 296 GNUNET_asprintf (&optpos, "%s%s%c%s", options, val, b, next);
307 } 297 GNUNET_free (options);
298 GNUNET_free (val);
299 options = optpos;
300 }
301 }
308 } 302 }
309 }
310 use_debug = GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name, "DEBUG"); 303 use_debug = GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name, "DEBUG");
311 304
305 /* actually start process */
312#if DEBUG_ARM 306#if DEBUG_ARM
313 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 307 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
314 "Starting service `%s' using binary `%s' and configuration `%s'\n", 308 "Starting service `%s' using binary `%s' and configuration `%s'\n",
315 sl->name, sl->binary, sl->config); 309 sl->name, sl->binary, sl->config);
316#endif 310#endif
317 if (GNUNET_YES == use_debug) 311 if (GNUNET_YES == use_debug)
318 sl->proc = 312 sl->proc =
319 do_start_process (lsocks, loprefix, sl->binary, "-c", sl->config, "-L", 313 do_start_process (lsocks, loprefix, sl->binary, "-c", sl->config, "-L",
320 "DEBUG", options, NULL); 314 "DEBUG", options, NULL);
321 else 315 else
322 sl->proc = 316 sl->proc =
323 do_start_process (lsocks, loprefix, sl->binary, "-c", sl->config, 317 do_start_process (lsocks, loprefix, sl->binary, "-c", sl->config,
324 options, NULL); 318 options, NULL);
325 if (sl->proc == NULL) 319 if (sl->proc == NULL)
326 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to start service `%s'\n"), 320 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to start service `%s'\n"),
327 sl->name); 321 sl->name);
328 else 322 else
329 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting service `%s'\n"), sl->name); 323 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting service `%s'\n"),
324 sl->name);
325 /* clean up */
330 GNUNET_free (loprefix); 326 GNUNET_free (loprefix);
331 GNUNET_free (options); 327 GNUNET_free (options);
332} 328 GNUNET_array_grow (lsocks, ls, 0);
333
334
335/**
336 * Put the default services represented by a space separated string into an array of strings
337 *
338 * @param services space separated string of default services
339 */
340static void
341addDefaultServicesToList (const char *services)
342{
343 unsigned int i;
344 const char *token;
345 char *s;
346
347 if (strlen (services) == 0)
348 return;
349 s = GNUNET_strdup (services);
350 token = strtok (s, " ");
351 while (NULL != token)
352 {
353 numDefaultServices++;
354 token = strtok (NULL, " ");
355 }
356 GNUNET_free (s);
357
358 defaultServicesList = GNUNET_malloc (numDefaultServices * sizeof (char *));
359 i = 0;
360 s = GNUNET_strdup (services);
361 token = strtok (s, " ");
362 while (NULL != token)
363 {
364 defaultServicesList[i++] = GNUNET_strdup (token);
365 token = strtok (NULL, " ");
366 }
367 GNUNET_free (s);
368 GNUNET_assert (i == numDefaultServices);
369}
370
371
372/**
373 * Checks whether the serviceName is in the list of default services
374 *
375 * @param serviceName string to check its existance in the list
376 * @return GNUNET_YES if the service is started by default
377 */
378static int
379isInDefaultList (const char *serviceName)
380{
381 unsigned int i;
382
383 for (i = 0; i < numDefaultServices; i++)
384 if (strcmp (serviceName, defaultServicesList[i]) == 0)
385 return GNUNET_YES;
386 return GNUNET_NO;
387}
388
389
390/**
391 *
392 */
393static int
394stop_listening (const char *serviceName)
395{
396 struct ServiceListeningInfo *pos;
397 struct ServiceListeningInfo *next;
398 int ret;
399
400 ret = GNUNET_NO;
401 next = serviceListeningInfoList_head;
402 while (NULL != (pos = next))
403 {
404 next = pos->next;
405 if ((serviceName != NULL) && (strcmp (pos->serviceName, serviceName) != 0))
406 continue;
407 if (pos->acceptTask != GNUNET_SCHEDULER_NO_TASK)
408 GNUNET_SCHEDULER_cancel (pos->acceptTask);
409 GNUNET_break (GNUNET_OK ==
410 GNUNET_NETWORK_socket_close (pos->listeningSocket));
411 GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head,
412 serviceListeningInfoList_tail, pos);
413 GNUNET_free (pos->serviceName);
414 GNUNET_free (pos->service_addr);
415 GNUNET_free (pos);
416 ret = GNUNET_OK;
417 }
418 return ret;
419} 329}
420 330
421 331
@@ -430,25 +340,26 @@ stop_listening (const char *serviceName)
430static size_t 340static size_t
431write_result (void *cls, size_t size, void *buf) 341write_result (void *cls, size_t size, void *buf)
432{ 342{
433 uint16_t *res = cls; 343 enum GNUNET_ARM_ProcessStatus *res = cls;
434 struct GNUNET_MessageHeader *msg; 344 struct GNUNET_ARM_ResultMessage *msg;
435 345
436 if (buf == NULL) 346 if (buf == NULL)
437 { 347 {
438 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 348 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
439 _("Could not send status result to client\n")); 349 _("Could not send status result to client\n"));
440 return 0; /* error, not much we can do */ 350 return 0; /* error, not much we can do */
441 } 351 }
442#if DEBUG_ARM 352#if DEBUG_ARM
443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending status response %u to client\n", 353 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
444 (unsigned int) *res); 354 "Sending status response %u to client\n", (unsigned int) *res);
445#endif 355#endif
446 GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); 356 GNUNET_assert (size >= sizeof (struct GNUNET_ARM_ResultMessage));
447 msg = buf; 357 msg = buf;
448 msg->size = htons (sizeof (struct GNUNET_MessageHeader)); 358 msg->header.size = htons (sizeof (struct GNUNET_ARM_ResultMessage));
449 msg->type = htons (*res); 359 msg->header.type = htons (GNUNET_MESSAGE_TYPE_ARM_RESULT);
360 msg->status = htonl ((uint32_t) (*res));
450 GNUNET_free (res); 361 GNUNET_free (res);
451 return sizeof (struct GNUNET_MessageHeader); 362 return sizeof (struct GNUNET_ARM_ResultMessage);
452} 363}
453 364
454 365
@@ -463,27 +374,21 @@ write_result (void *cls, size_t size, void *buf)
463 */ 374 */
464static void 375static void
465signal_result (struct GNUNET_SERVER_Client *client, const char *name, 376signal_result (struct GNUNET_SERVER_Client *client, const char *name,
466 uint16_t result) 377 enum GNUNET_ARM_ProcessStatus result)
467{ 378{
468 uint16_t *res; 379 enum GNUNET_ARM_ProcessStatus *res;
469 380
470 if (NULL == client) 381 if (NULL == client)
471 {
472 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
473 _("Not sending status result to client: no client known\n"));
474 return; 382 return;
475 } 383 /* FIXME: this is not super-clean yet... */
476#if DEBUG_ARM 384 res = GNUNET_malloc (sizeof (enum GNUNET_ARM_ProcessStatus));
477 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
478 "Telling client that service `%s' is now %s\n", name,
479 result == GNUNET_MESSAGE_TYPE_ARM_IS_DOWN ? "down" : "up");
480#endif
481 res = GNUNET_malloc (sizeof (uint16_t));
482 *res = result; 385 *res = result;
483 GNUNET_SERVER_notify_transmit_ready (client, 386 GNUNET_SERVER_notify_transmit_ready (client,
484 sizeof (struct GNUNET_MessageHeader), 387 sizeof (struct
485 GNUNET_TIME_UNIT_FOREVER_REL, 388 GNUNET_ARM_ResultMessage),
486 &write_result, res); 389 GNUNET_TIME_UNIT_FOREVER_REL,
390 &write_result, res);
391 GNUNET_SERVER_receive_done (client, GNUNET_OK);
487} 392}
488 393
489 394
@@ -497,88 +402,16 @@ signal_result (struct GNUNET_SERVER_Client *client, const char *name,
497static struct ServiceList * 402static struct ServiceList *
498find_service (const char *name) 403find_service (const char *name)
499{ 404{
500 struct ServiceList *pos;
501
502 pos = running_head;
503 while (pos != NULL)
504 {
505 if (0 == strcmp (pos->name, name))
506 return pos;
507 pos = pos->next;
508 }
509 return NULL;
510}
511
512
513/**
514 * Start the specified service.
515 *
516 * @param client who is asking for this
517 * @param servicename name of the service to start
518 * @param lsocks -1 terminated list of listen sockets to pass (systemd style), or NULL
519 * @return GNUNET_OK on success, GNUNET_SYSERR on error
520 */
521static int
522start_service (struct GNUNET_SERVER_Client *client, const char *servicename,
523 const SOCKTYPE *lsocks)
524{
525 struct ServiceList *sl; 405 struct ServiceList *sl;
526 char *binary;
527 char *config;
528 struct stat sbuf;
529 406
530 if (GNUNET_YES == in_shutdown) 407 sl = running_head;
531 { 408 while (sl != NULL)
532 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 409 {
533 _("ARM is shutting down, service `%s' not started.\n"), 410 if (0 == strcmp (sl->name, name))
534 servicename); 411 return sl;
535 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN); 412 sl = sl->next;
536 return GNUNET_SYSERR; 413 }
537 } 414 return NULL;
538 sl = find_service (servicename);
539 if (sl != NULL)
540 {
541 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Service `%s' already running.\n"),
542 servicename);
543 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_UP);
544 return GNUNET_SYSERR;
545 }
546 if (GNUNET_OK !=
547 GNUNET_CONFIGURATION_get_value_string (cfg, servicename, "BINARY",
548 &binary))
549 {
550 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
551 _("Binary implementing service `%s' not known!\n"),
552 servicename);
553 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
554 return GNUNET_SYSERR;
555 }
556 if ((GNUNET_OK !=
557 GNUNET_CONFIGURATION_get_value_filename (cfg, servicename, "CONFIG",
558 &config)) ||
559 (0 != STAT (config, &sbuf)))
560 {
561 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
562 _("Configuration file `%s' for service `%s' not known!\n"),
563 config, servicename);
564 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
565 GNUNET_free (binary);
566 GNUNET_free_non_null (config);
567 return GNUNET_SYSERR;
568 }
569 (void) stop_listening (servicename);
570 sl = GNUNET_malloc (sizeof (struct ServiceList));
571 sl->name = GNUNET_strdup (servicename);
572 sl->binary = binary;
573 sl->config = config;
574 sl->mtime = sbuf.st_mtime;
575 sl->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
576 sl->restartAt = GNUNET_TIME_UNIT_FOREVER_ABS;
577 GNUNET_CONTAINER_DLL_insert (running_head, running_tail, sl);
578 start_process (sl, lsocks);
579 if (NULL != client)
580 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_UP);
581 return GNUNET_OK;
582} 415}
583 416
584 417
@@ -590,58 +423,15 @@ start_service (struct GNUNET_SERVER_Client *client, const char *servicename,
590 * @param tc context 423 * @param tc context
591 */ 424 */
592static void 425static void
593acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 426accept_connection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
594{ 427{
595 struct ServiceListeningInfo *sli = cls; 428 struct ServiceListeningInfo *sli = cls;
596 struct ServiceListeningInfo *pos; 429 struct ServiceList *sl = sli->sl;
597 struct ServiceListeningInfo *next;
598 SOCKTYPE *lsocks;
599 unsigned int ls;
600 430
601 sli->acceptTask = GNUNET_SCHEDULER_NO_TASK; 431 sli->accept_task = GNUNET_SCHEDULER_NO_TASK;
602 if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) 432 if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
603 return; 433 return;
604 GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head, 434 start_process (sl);
605 serviceListeningInfoList_tail, sli);
606 lsocks = NULL;
607 ls = 0;
608 next = serviceListeningInfoList_head;
609 while (NULL != (pos = next))
610 {
611 next = pos->next;
612 if (0 == strcmp (pos->serviceName, sli->serviceName))
613 {
614 GNUNET_array_append (lsocks, ls,
615 GNUNET_NETWORK_get_fd (pos->listeningSocket));
616 GNUNET_free (pos->listeningSocket); /* deliberately no closing! */
617 GNUNET_free (pos->service_addr);
618 GNUNET_free (pos->serviceName);
619 GNUNET_SCHEDULER_cancel (pos->acceptTask);
620 GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head,
621 serviceListeningInfoList_tail, pos);
622 GNUNET_free (pos);
623 }
624 }
625 GNUNET_array_append (lsocks, ls,
626 GNUNET_NETWORK_get_fd (sli->listeningSocket));
627 GNUNET_free (sli->listeningSocket); /* deliberately no closing! */
628 GNUNET_free (sli->service_addr);
629#if WINDOWS
630 GNUNET_array_append (lsocks, ls, INVALID_SOCKET);
631#else
632 GNUNET_array_append (lsocks, ls, -1);
633#endif
634 start_service (NULL, sli->serviceName, lsocks);
635 ls = 0;
636 while (lsocks[ls] != -1)
637#if WINDOWS
638 GNUNET_break (0 == closesocket (lsocks[ls++]));
639#else
640 GNUNET_break (0 == close (lsocks[ls++]));
641#endif
642 GNUNET_array_grow (lsocks, ls, 0);
643 GNUNET_free (sli->serviceName);
644 GNUNET_free (sli);
645} 435}
646 436
647 437
@@ -651,263 +441,104 @@ acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
651 * 441 *
652 * @param sa address associated with the service 442 * @param sa address associated with the service
653 * @param addr_len length of sa 443 * @param addr_len length of sa
654 * @param serviceName the name of the service in question 444 * @param sl service entry for the service in question
655 */ 445 */
656static void 446static void
657createListeningSocket (struct sockaddr *sa, socklen_t addr_len, 447create_listen_socket (struct sockaddr *sa, socklen_t addr_len,
658 const char *serviceName) 448 struct ServiceList *sl)
659{ 449{
660 const static int on = 1; 450 const static int on = 1;
661 struct GNUNET_NETWORK_Handle *sock; 451 struct GNUNET_NETWORK_Handle *sock;
662 struct ServiceListeningInfo *serviceListeningInfo; 452 struct ServiceListeningInfo *sli;
663 453
664 switch (sa->sa_family) 454 switch (sa->sa_family)
665 { 455 {
666 case AF_INET: 456 case AF_INET:
667 sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0); 457 sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
668 break; 458 break;
669 case AF_INET6: 459 case AF_INET6:
670 sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); 460 sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
671 break; 461 break;
672 case AF_UNIX: 462 case AF_UNIX:
673 if (strcmp (GNUNET_a2s (sa, addr_len), "@") == 0) /* Do not bind to blank UNIX path! */ 463 if (strcmp (GNUNET_a2s (sa, addr_len), "@") == 0) /* Do not bind to blank UNIX path! */
674 return; 464 return;
675 sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0); 465 sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
676 break; 466 break;
677 default: 467 default:
678 GNUNET_break (0); 468 GNUNET_break (0);
679 sock = NULL; 469 sock = NULL;
680 errno = EAFNOSUPPORT; 470 errno = EAFNOSUPPORT;
681 break; 471 break;
682 } 472 }
683 if (NULL == sock) 473 if (NULL == sock)
684 { 474 {
685 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 475 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
686 _("Unable to create socket for service `%s': %s\n"), 476 _("Unable to create socket for service `%s': %s\n"),
687 serviceName, STRERROR (errno)); 477 sl->name, STRERROR (errno));
688 GNUNET_free (sa); 478 GNUNET_free (sa);
689 return; 479 return;
690 } 480 }
691 if (GNUNET_NETWORK_socket_setsockopt 481 if (GNUNET_NETWORK_socket_setsockopt
692 (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) 482 (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
693 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 483 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
694 "setsockopt"); 484 "setsockopt");
695#ifdef IPV6_V6ONLY 485#ifdef IPV6_V6ONLY
696 if ((sa->sa_family == AF_INET6) && 486 if ((sa->sa_family == AF_INET6) &&
697 (GNUNET_NETWORK_socket_setsockopt 487 (GNUNET_NETWORK_socket_setsockopt
698 (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK)) 488 (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK))
699 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 489 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
700 "setsockopt"); 490 "setsockopt");
701#endif 491#endif
702 492
703 if (GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) sa, addr_len) 493 if (GNUNET_NETWORK_socket_bind
704 != GNUNET_OK) 494 (sock, (const struct sockaddr *) sa, addr_len) != GNUNET_OK)
705 { 495 {
706 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 496 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
707 _ 497 _
708 ("Unable to bind listening socket for service `%s' to address `%s': %s\n"), 498 ("Unable to bind listening socket for service `%s' to address `%s': %s\n"),
709 serviceName, GNUNET_a2s (sa, addr_len), STRERROR (errno)); 499 sl->name, GNUNET_a2s (sa, addr_len), STRERROR (errno));
710 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); 500 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
711 GNUNET_free (sa); 501 GNUNET_free (sa);
712 return; 502 return;
713 } 503 }
714 if (GNUNET_NETWORK_socket_listen (sock, 5) != GNUNET_OK) 504 if (GNUNET_NETWORK_socket_listen (sock, 5) != GNUNET_OK)
715 {
716 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
717 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
718 GNUNET_free (sa);
719 return;
720 }
721 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
722 _("ARM now monitors connections to service `%s' at `%s'\n"),
723 serviceName, GNUNET_a2s (sa, addr_len));
724 serviceListeningInfo = GNUNET_malloc (sizeof (struct ServiceListeningInfo));
725 serviceListeningInfo->serviceName = GNUNET_strdup (serviceName);
726 serviceListeningInfo->service_addr = sa;
727 serviceListeningInfo->service_addr_len = addr_len;
728 serviceListeningInfo->listeningSocket = sock;
729 serviceListeningInfo->acceptTask =
730 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sock,
731 &acceptConnection, serviceListeningInfo);
732 GNUNET_CONTAINER_DLL_insert (serviceListeningInfoList_head,
733 serviceListeningInfoList_tail,
734 serviceListeningInfo);
735}
736
737
738/**
739 * Callback function, checks whether the current tokens are representing a service,
740 * gets its addresses and create listening socket for it.
741 *
742 * @param cls callback data, not used
743 * @param section configuration section
744 * @param option configuration option
745 * @param value the option's value
746 */
747static void
748checkPortNumberCB (void *cls, const char *section, const char *option,
749 const char *value)
750{
751 struct sockaddr **addrs;
752 socklen_t *addr_lens;
753 int ret;
754 unsigned int i;
755
756 if ((strcasecmp (section, "arm") == 0) ||
757 (strcasecmp (option, "AUTOSTART") != 0) ||
758 (strcasecmp (value, "YES") != 0) ||
759 (isInDefaultList (section) == GNUNET_YES))
760 return;
761 if (0 >=
762 (ret =
763 GNUNET_SERVICE_get_server_addresses (section, cfg, &addrs, &addr_lens)))
764 return;
765 /* this will free (or capture) addrs[i] */
766 for (i = 0; i < ret; i++)
767 createListeningSocket (addrs[i], addr_lens[i], section);
768 GNUNET_free (addrs);
769 GNUNET_free (addr_lens);
770}
771
772
773/**
774 * Entry point to the Service Manager
775 *
776 * @param configurationHandle configuration to use to get services
777 */
778static void
779prepare_services (const struct GNUNET_CONFIGURATION_Handle *configurationHandle)
780{
781 char *defaultServicesString;
782
783 cfg = configurationHandle;
784 /* Split the default services into a list */
785 if (GNUNET_OK ==
786 GNUNET_CONFIGURATION_get_value_string (cfg, "arm", "DEFAULTSERVICES",
787 &defaultServicesString))
788 {
789 addDefaultServicesToList (defaultServicesString);
790 GNUNET_free (defaultServicesString);
791 }
792 /* Spot the services from the configuration and create a listening
793 * socket for each */
794 GNUNET_CONFIGURATION_iterate (cfg, &checkPortNumberCB, NULL);
795}
796
797
798
799/**
800 * If the configuration file changes, restart tasks that depended on that
801 * option.
802 *
803 * @param cls closure, NULL if we need to self-restart
804 * @param tc context
805 */
806static void
807config_change_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
808{
809 struct ServiceList *pos;
810 struct stat sbuf;
811
812 pos = running_head;
813 while (pos != NULL)
814 {
815 /* FIXME: this test for config change may be a bit too coarse grained */
816 if ((0 == STAT (pos->config, &sbuf)) && (pos->mtime < sbuf.st_mtime) &&
817 (pos->proc != NULL))
818 { 505 {
819 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 506 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
820 _ 507 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
821 ("Restarting service `%s' due to configuration file change.\n")); 508 GNUNET_free (sa);
822 if (0 != GNUNET_OS_process_kill (pos->proc, SIGTERM)) 509 return;
823 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
824 else
825 pos->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
826 } 510 }
827 pos = pos->next; 511 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
828 } 512 _("ARM now monitors connections to service `%s' at `%s'\n"),
829} 513 sl->name, GNUNET_a2s (sa, addr_len));
830 514 sli = GNUNET_malloc (sizeof (struct ServiceListeningInfo));
831 515 sli->service_addr = sa;
832/** 516 sli->service_addr_len = addr_len;
833 * Remove and free an entry in the service list. 517 sli->listen_socket = sock;
834 * 518 sli->sl = sl;
835 * @param pos entry to free 519 sli->accept_task =
836 */ 520 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sock,
837static void 521 &accept_connection, sli);
838free_service (struct ServiceList *pos) 522 GNUNET_CONTAINER_DLL_insert (sl->listen_head, sl->listen_tail, sli);
839{
840 GNUNET_CONTAINER_DLL_remove (running_head, running_tail, pos);
841 GNUNET_free_non_null (pos->config);
842 GNUNET_free_non_null (pos->binary);
843 GNUNET_free (pos->name);
844 GNUNET_free (pos);
845} 523}
846 524
847 525
848/** 526/**
849 * Stop the specified service. 527 * Remove and free an entry in the service list. Listen sockets
528 * must have already been cleaned up. Only to be called during shutdown.
850 * 529 *
851 * @param client who is asking for this 530 * @param sl entry to free
852 * @param servicename name of the service to stop
853 */ 531 */
854static void 532static void
855stop_service (struct GNUNET_SERVER_Client *client, const char *servicename) 533free_service (struct ServiceList *sl)
856{ 534{
857 struct ServiceList *pos; 535 GNUNET_assert (GNUNET_YES == in_shutdown);
858 536 GNUNET_CONTAINER_DLL_remove (running_head, running_tail, sl);
859 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Preparing to stop `%s'\n"), 537 GNUNET_assert (NULL == sl->listen_head);
860 servicename); 538 GNUNET_free_non_null (sl->config);
861 pos = find_service (servicename); 539 GNUNET_free_non_null (sl->binary);
862 if (pos == NULL) 540 GNUNET_free (sl->name);
863 { 541 GNUNET_free (sl);
864 if (GNUNET_OK == stop_listening (servicename))
865 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
866 else
867 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_UNKNOWN);
868 GNUNET_SERVER_receive_done (client, GNUNET_OK);
869 return;
870 }
871 if (pos->killing_client != NULL)
872 {
873 /* killing already in progress */
874#if DEBUG_ARM
875 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' is already down\n",
876 servicename);
877#endif
878 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
879 GNUNET_SERVER_receive_done (client, GNUNET_OK);
880 return;
881 }
882
883 if (GNUNET_YES == in_shutdown)
884 {
885#if DEBUG_ARM
886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
887 "Termination request already sent to `%s' (since ARM is in shutdown).\n",
888 servicename);
889#endif
890 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
891 GNUNET_SERVER_receive_done (client, GNUNET_OK);
892 return;
893 }
894 if (pos->proc == NULL)
895 {
896 /* process is in delayed restart, simply remove it! */
897 free_service (pos);
898 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
899 GNUNET_SERVER_receive_done (client, GNUNET_OK);
900 return;
901 }
902#if DEBUG_ARM
903 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
904 "Sending kill signal to service `%s', waiting for process to die.\n",
905 servicename);
906#endif
907 if (0 != GNUNET_OS_process_kill (pos->proc, SIGTERM))
908 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
909 pos->killing_client = client;
910 GNUNET_SERVER_client_keep (client);
911} 542}
912 543
913 544
@@ -922,22 +553,40 @@ stop_service (struct GNUNET_SERVER_Client *client, const char *servicename)
922 */ 553 */
923static void 554static void
924handle_start (void *cls, struct GNUNET_SERVER_Client *client, 555handle_start (void *cls, struct GNUNET_SERVER_Client *client,
925 const struct GNUNET_MessageHeader *message) 556 const struct GNUNET_MessageHeader *message)
926{ 557{
927 const char *servicename; 558 const char *servicename;
559 struct ServiceList *sl;
928 uint16_t size; 560 uint16_t size;
929 561
930 size = ntohs (message->size); 562 size = ntohs (message->size);
931 size -= sizeof (struct GNUNET_MessageHeader); 563 size -= sizeof (struct GNUNET_MessageHeader);
932 servicename = (const char *) &message[1]; 564 servicename = (const char *) &message[1];
933 if ((size == 0) || (servicename[size - 1] != '\0')) 565 if ((size == 0) || (servicename[size - 1] != '\0'))
934 { 566 {
935 GNUNET_break (0); 567 GNUNET_break (0);
936 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); 568 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
937 return; 569 return;
938 } 570 }
939 start_service (client, servicename, NULL); 571 if (GNUNET_YES == in_shutdown)
940 GNUNET_SERVER_receive_done (client, GNUNET_OK); 572 {
573 signal_result (client, servicename, GNUNET_ARM_PROCESS_SHUTDOWN);
574 return;
575 }
576 sl = find_service (servicename);
577 if (NULL == sl)
578 {
579 signal_result (client, servicename, GNUNET_ARM_PROCESS_UNKNOWN);
580 return;
581 }
582 sl->is_default = GNUNET_YES;
583 if (sl->proc != NULL)
584 {
585 signal_result (client, servicename, GNUNET_ARM_PROCESS_ALREADY_RUNNING);
586 return;
587 }
588 start_process (sl);
589 signal_result (client, servicename, GNUNET_ARM_PROCESS_STARTING);
941} 590}
942 591
943 592
@@ -952,8 +601,9 @@ handle_start (void *cls, struct GNUNET_SERVER_Client *client,
952 */ 601 */
953static void 602static void
954handle_stop (void *cls, struct GNUNET_SERVER_Client *client, 603handle_stop (void *cls, struct GNUNET_SERVER_Client *client,
955 const struct GNUNET_MessageHeader *message) 604 const struct GNUNET_MessageHeader *message)
956{ 605{
606 struct ServiceList *sl;
957 const char *servicename; 607 const char *servicename;
958 uint16_t size; 608 uint16_t size;
959 609
@@ -961,33 +611,48 @@ handle_stop (void *cls, struct GNUNET_SERVER_Client *client,
961 size -= sizeof (struct GNUNET_MessageHeader); 611 size -= sizeof (struct GNUNET_MessageHeader);
962 servicename = (const char *) &message[1]; 612 servicename = (const char *) &message[1];
963 if ((size == 0) || (servicename[size - 1] != '\0')) 613 if ((size == 0) || (servicename[size - 1] != '\0'))
964 { 614 {
965 GNUNET_break (0); 615 GNUNET_break (0);
966 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); 616 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
967 return; 617 return;
968 } 618 }
969 stop_service (client, servicename); 619 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
970} 620 _("Preparing to stop `%s'\n"), servicename);
971 621 sl = find_service (servicename);
972 622 if (sl == NULL)
973/** 623 {
974 * Remove all entries for tasks that are not running 624 signal_result (client, servicename, GNUNET_ARM_PROCESS_UNKNOWN);
975 * (proc = NULL) from the running list (they will no longer 625 return;
976 * be restarted since we are shutting down). 626 }
977 */ 627 sl->is_default = GNUNET_NO;
978static void 628 if (GNUNET_YES == in_shutdown)
979clean_up_running () 629 {
980{ 630 /* shutdown in progress */
981 struct ServiceList *pos; 631 signal_result (client, servicename, GNUNET_ARM_PROCESS_SHUTDOWN);
982 struct ServiceList *next; 632 return;
983 633 }
984 next = running_head; 634 if (sl->killing_client != NULL)
985 while (NULL != (pos = next)) 635 {
986 { 636 /* killing already in progress */
987 next = pos->next; 637 signal_result (client, servicename,
988 if (pos->proc == NULL) 638 GNUNET_ARM_PROCESS_ALREADY_STOPPING);
989 free_service (pos); 639 return;
990 } 640 }
641 if (sl->proc == NULL)
642 {
643 /* process is down */
644 signal_result (client, servicename, GNUNET_ARM_PROCESS_ALREADY_DOWN);
645 return;
646 }
647#if DEBUG_ARM
648 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
649 "Sending kill signal to service `%s', waiting for process to die.\n",
650 servicename);
651#endif
652 if (0 != GNUNET_OS_process_kill (sl->proc, SIGTERM))
653 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
654 sl->killing_client = client;
655 GNUNET_SERVER_client_keep (client);
991} 656}
992 657
993 658
@@ -999,15 +664,15 @@ static void
999do_shutdown () 664do_shutdown ()
1000{ 665{
1001 if (NULL != server) 666 if (NULL != server)
1002 { 667 {
1003 GNUNET_SERVER_destroy (server); 668 GNUNET_SERVER_destroy (server);
1004 server = NULL; 669 server = NULL;
1005 } 670 }
1006 if (GNUNET_SCHEDULER_NO_TASK != child_death_task) 671 if (GNUNET_SCHEDULER_NO_TASK != child_death_task)
1007 { 672 {
1008 GNUNET_SCHEDULER_cancel (child_death_task); 673 GNUNET_SCHEDULER_cancel (child_death_task);
1009 child_death_task = GNUNET_SCHEDULER_NO_TASK; 674 child_death_task = GNUNET_SCHEDULER_NO_TASK;
1010 } 675 }
1011} 676}
1012 677
1013 678
@@ -1022,33 +687,50 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1022{ 687{
1023 struct ServiceList *pos; 688 struct ServiceList *pos;
1024 struct ServiceList *nxt; 689 struct ServiceList *nxt;
690 struct ServiceListeningInfo *sli;
1025 691
1026#if DEBUG_ARM
1027 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Stopping all services\n"));
1028#endif
1029 if (GNUNET_SCHEDULER_NO_TASK != child_restart_task) 692 if (GNUNET_SCHEDULER_NO_TASK != child_restart_task)
1030 { 693 {
1031 GNUNET_SCHEDULER_cancel (child_restart_task); 694 GNUNET_SCHEDULER_cancel (child_restart_task);
1032 child_restart_task = GNUNET_SCHEDULER_NO_TASK; 695 child_restart_task = GNUNET_SCHEDULER_NO_TASK;
1033 } 696 }
1034 in_shutdown = GNUNET_YES; 697 in_shutdown = GNUNET_YES;
1035 stop_listening (NULL); 698 /* first, stop listening */
1036 pos = running_head; 699 for (pos = running_head; NULL != pos; pos = pos->next)
1037 while (NULL != pos)
1038 {
1039 nxt = pos->next;
1040 if (pos->proc != NULL)
1041 { 700 {
1042 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping service `%s'\n", pos->name); 701 while (NULL != (sli = pos->listen_head))
1043 if (0 != GNUNET_OS_process_kill (pos->proc, SIGTERM)) 702 {
1044 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); 703 GNUNET_CONTAINER_DLL_remove (pos->listen_head,
704 pos->listen_tail, sli);
705 if (sli->accept_task != GNUNET_SCHEDULER_NO_TASK)
706 {
707 GNUNET_SCHEDULER_cancel (sli->accept_task);
708 sli->accept_task = GNUNET_SCHEDULER_NO_TASK;
709 }
710 GNUNET_break (GNUNET_OK ==
711 GNUNET_NETWORK_socket_close (sli->listen_socket));
712 GNUNET_free (sli->service_addr);
713 GNUNET_free (sli);
714 }
1045 } 715 }
1046 else 716 /* then, shutdown all existing service processes */
717 nxt = running_head;
718 while (NULL != (pos = nxt))
1047 { 719 {
1048 free_service (pos); 720 nxt = pos->next;
721 if (pos->proc != NULL)
722 {
723 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping service `%s'\n",
724 pos->name);
725 if (0 != GNUNET_OS_process_kill (pos->proc, SIGTERM))
726 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
727 }
728 else
729 {
730 free_service (pos);
731 }
1049 } 732 }
1050 pos = nxt; 733 /* finally, should all service processes be already gone, terminate for real */
1051 }
1052 if (running_head == NULL) 734 if (running_head == NULL)
1053 do_shutdown (); 735 do_shutdown ();
1054} 736}
@@ -1061,10 +743,12 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1061 * @param tc context 743 * @param tc context
1062 */ 744 */
1063static void 745static void
1064delayed_restart_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 746delayed_restart_task (void *cls,
747 const struct GNUNET_SCHEDULER_TaskContext *tc)
1065{ 748{
1066 struct ServiceList *pos; 749 struct ServiceList *sl;
1067 struct GNUNET_TIME_Relative lowestRestartDelay; 750 struct GNUNET_TIME_Relative lowestRestartDelay;
751 struct ServiceListeningInfo *sli;
1068 752
1069 child_restart_task = GNUNET_SCHEDULER_NO_TASK; 753 child_restart_task = GNUNET_SCHEDULER_NO_TASK;
1070 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) 754 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
@@ -1074,37 +758,56 @@ delayed_restart_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1074 758
1075 /* check for services that need to be restarted due to 759 /* check for services that need to be restarted due to
1076 * configuration changes or because the last restart failed */ 760 * configuration changes or because the last restart failed */
1077 pos = running_head; 761 for (sl = running_head; NULL != sl; sl = sl->next)
1078 while (pos != NULL)
1079 {
1080 if (pos->proc == NULL)
1081 { 762 {
1082 if (GNUNET_TIME_absolute_get_remaining (pos->restartAt).rel_value == 0) 763 if (sl->proc == NULL)
1083 { 764 {
1084 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Restarting service `%s'.\n"), 765 /* service is currently not running */
1085 pos->name); 766 if (GNUNET_TIME_absolute_get_remaining (sl->restart_at).rel_value ==
1086 start_process (pos, NULL); 767 0)
1087 } 768 {
1088 else 769 /* restart is now allowed */
1089 { 770 if (sl->is_default)
1090 lowestRestartDelay = 771 {
1091 GNUNET_TIME_relative_min (lowestRestartDelay, 772 /* process should run by default, start immediately */
1092 GNUNET_TIME_absolute_get_remaining 773 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1093 (pos->restartAt)); 774 _("Restarting service `%s'.\n"), sl->name);
1094 } 775 start_process (sl);
776 }
777 else
778 {
779 /* process is run on-demand, ensure it is re-started if there is demand */
780 for (sli = sl->listen_head; NULL != sli; sli = sli->next)
781 if (GNUNET_SCHEDULER_NO_TASK == sli->accept_task)
782 {
783 /* accept was actually paused, so start it again */
784 sli->accept_task =
785 GNUNET_SCHEDULER_add_read_net
786 (GNUNET_TIME_UNIT_FOREVER_REL, sli->listen_socket,
787 &accept_connection, sli);
788 }
789 }
790 }
791 else
792 {
793 /* update calculation for earliest time to reactivate a service */
794 lowestRestartDelay =
795 GNUNET_TIME_relative_min (lowestRestartDelay,
796 GNUNET_TIME_absolute_get_remaining
797 (sl->restart_at));
798 }
799 }
1095 } 800 }
1096 pos = pos->next;
1097 }
1098 if (lowestRestartDelay.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value) 801 if (lowestRestartDelay.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1099 { 802 {
1100#if DEBUG_ARM 803#if DEBUG_ARM
1101 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Will restart process in %llums\n", 804 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Will restart process in %llums\n",
1102 (unsigned long long) lowestRestartDelay.rel_value); 805 (unsigned long long) lowestRestartDelay.rel_value);
1103#endif 806#endif
1104 child_restart_task = 807 child_restart_task =
1105 GNUNET_SCHEDULER_add_delayed (lowestRestartDelay, &delayed_restart_task, 808 GNUNET_SCHEDULER_add_delayed (lowestRestartDelay,
1106 NULL); 809 &delayed_restart_task, NULL);
1107 } 810 }
1108} 811}
1109 812
1110 813
@@ -1120,126 +823,150 @@ maint_child_death (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1120{ 823{
1121 struct ServiceList *pos; 824 struct ServiceList *pos;
1122 struct ServiceList *next; 825 struct ServiceList *next;
826 struct ServiceListeningInfo *sli;
1123 const char *statstr; 827 const char *statstr;
1124 int statcode; 828 int statcode;
1125 int ret; 829 int ret;
1126 char c[16]; 830 char c[16];
1127 enum GNUNET_OS_ProcessStatusType statusType; 831 enum GNUNET_OS_ProcessStatusType statusType;
1128 unsigned long statusCode; 832 unsigned long statusCode;
833 const struct GNUNET_DISK_FileHandle *pr;
1129 834
835 pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
1130 child_death_task = GNUNET_SCHEDULER_NO_TASK; 836 child_death_task = GNUNET_SCHEDULER_NO_TASK;
1131 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) 837 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
1132 { 838 {
1133 /* shutdown scheduled us, ignore! */ 839 /* shutdown scheduled us, ignore! */
1134 child_death_task = 840 child_death_task =
1135 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, pr, 841 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1136 &maint_child_death, NULL); 842 pr, &maint_child_death, NULL);
1137 return; 843 return;
1138 } 844 }
1139 /* consume the signal */ 845 /* consume the signal */
1140 GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c))); 846 GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
1141 847
1142 /* check for services that died (WAITPID) */ 848 /* check for services that died (WAITPID) */
1143 next = running_head; 849 next = running_head;
1144 while (NULL != (pos = next)) 850 while (NULL != (pos = next))
1145 {
1146 next = pos->next;
1147 if (pos->proc == NULL)
1148 continue;
1149 if ((GNUNET_SYSERR ==
1150 (ret = GNUNET_OS_process_status (pos->proc, &statusType, &statusCode)))
1151 || ((ret == GNUNET_NO) || (statusType == GNUNET_OS_PROCESS_STOPPED) ||
1152 (statusType == GNUNET_OS_PROCESS_RUNNING)))
1153 continue;
1154
1155 if (statusType == GNUNET_OS_PROCESS_EXITED)
1156 {
1157 statstr = _( /* process termination method */ "exit");
1158 statcode = statusCode;
1159 }
1160 else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
1161 {
1162 statstr = _( /* process termination method */ "signal");
1163 statcode = statusCode;
1164 }
1165 else
1166 {
1167 statstr = _( /* process termination method */ "unknown");
1168 statcode = 0;
1169 }
1170 GNUNET_OS_process_close (pos->proc);
1171 pos->proc = NULL;
1172 if (NULL != pos->killing_client)
1173 {
1174 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Service `%s' stopped\n"),
1175 pos->name);
1176 signal_result (pos->killing_client, pos->name,
1177 GNUNET_MESSAGE_TYPE_ARM_IS_DOWN);
1178 GNUNET_SERVER_receive_done (pos->killing_client, GNUNET_OK);
1179 GNUNET_SERVER_client_drop (pos->killing_client);
1180 free_service (pos);
1181 continue;
1182 }
1183 if (GNUNET_YES != in_shutdown)
1184 { 851 {
1185 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) 852 next = pos->next;
1186 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 853
1187 _ 854 if (pos->proc == NULL)
1188 ("Service `%s' terminated with status %s/%d, will try to restart it!\n"), 855 {
1189 pos->name, statstr, statcode); 856 if (GNUNET_YES == in_shutdown)
1190 /* schedule restart */ 857 free_service (pos);
1191 pos->restartAt = GNUNET_TIME_relative_to_absolute (pos->backoff); 858 continue;
1192 if (pos->backoff.rel_value < EXPONENTIAL_BACKOFF_THRESHOLD) 859 }
1193 pos->backoff = GNUNET_TIME_relative_multiply (pos->backoff, 2); 860 if ((GNUNET_SYSERR ==
1194 if (GNUNET_SCHEDULER_NO_TASK != child_restart_task) 861 (ret =
1195 GNUNET_SCHEDULER_cancel (child_restart_task); 862 GNUNET_OS_process_status (pos->proc, &statusType, &statusCode)))
1196 child_restart_task = 863 || ((ret == GNUNET_NO) || (statusType == GNUNET_OS_PROCESS_STOPPED)
1197 GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, 864 || (statusType == GNUNET_OS_PROCESS_RUNNING)))
1198 &delayed_restart_task, NULL); 865 continue;
866 if (statusType == GNUNET_OS_PROCESS_EXITED)
867 {
868 statstr = _( /* process termination method */ "exit");
869 statcode = statusCode;
870 }
871 else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
872 {
873 statstr = _( /* process termination method */ "signal");
874 statcode = statusCode;
875 }
876 else
877 {
878 statstr = _( /* process termination method */ "unknown");
879 statcode = 0;
880 }
881 GNUNET_OS_process_close (pos->proc);
882 pos->proc = NULL;
883 if (NULL != pos->killing_client)
884 {
885 signal_result (pos->killing_client, pos->name,
886 GNUNET_ARM_PROCESS_DOWN);
887 GNUNET_SERVER_client_drop (pos->killing_client);
888 pos->killing_client = NULL;
889 /* process can still be re-started on-demand, ensure it is re-started if there is demand */
890 for (sli = pos->listen_head; NULL != sli; sli = sli->next)
891 {
892 GNUNET_break (GNUNET_SCHEDULER_NO_TASK == sli->accept_task);
893 sli->accept_task =
894 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
895 sli->listen_socket,
896 &accept_connection, sli);
897 }
898 continue;
899 }
900 if (GNUNET_YES != in_shutdown)
901 {
902 if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0))
903 {
904 /* process terminated normally, allow restart at any time */
905 pos->restart_at.abs_value = 0;
906 continue;
907 }
908 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
909 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
910 _
911 ("Service `%s' terminated with status %s/%d, will restart in %llu ms\n"),
912 pos->name, statstr, statcode, pos->backoff.rel_value);
913 /* schedule restart */
914 pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff);
915 pos->backoff =
916 GNUNET_TIME_relative_min (EXPONENTIAL_BACKOFF_THRESHOLD,
917 GNUNET_TIME_relative_multiply
918 (pos->backoff, 2));
919 if (GNUNET_SCHEDULER_NO_TASK != child_restart_task)
920 GNUNET_SCHEDULER_cancel (child_restart_task);
921 child_restart_task =
922 GNUNET_SCHEDULER_add_with_priority
923 (GNUNET_SCHEDULER_PRIORITY_IDLE, &delayed_restart_task, NULL);
924 }
925 else
926 {
927 free_service (pos);
928 }
1199 } 929 }
1200#if DEBUG_ARM
1201 else
1202 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1203 "Service `%s' terminated with status %s/%d\n", pos->name,
1204 statstr, statcode);
1205#endif
1206 }
1207 child_death_task = 930 child_death_task =
1208 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, pr, 931 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1209 &maint_child_death, NULL); 932 pr, &maint_child_death, NULL);
1210 if (GNUNET_YES == in_shutdown)
1211 clean_up_running ();
1212 if ((NULL == running_head) && (GNUNET_YES == in_shutdown)) 933 if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
1213 do_shutdown (); 934 do_shutdown ();
1214} 935}
1215 936
1216 937
938/**
939 * Transmit our shutdown acknowledgement to the client.
940 *
941 * @param cls the 'struct GNUNET_SERVER_Client'
942 * @param size number of bytes available in buf
943 * @param buf where to write the message
944 * @return number of bytes written
945 */
1217static size_t 946static size_t
1218transmit_shutdown_ack (void *cls, size_t size, void *buf) 947transmit_shutdown_ack (void *cls, size_t size, void *buf)
1219{ 948{
1220 struct GNUNET_SERVER_Client *client = cls; 949 struct GNUNET_SERVER_Client *client = cls;
1221 struct GNUNET_MessageHeader *msg; 950 struct GNUNET_ARM_ResultMessage *msg;
1222
1223 if (size < sizeof (struct GNUNET_MessageHeader))
1224 {
1225 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1226 _("Failed to transmit shutdown ACK.\n"));
1227 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1228 return 0; /* client disconnected */
1229 }
1230
1231 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transmitting shutdown ACK.\n"));
1232 951
952 if (size < sizeof (struct GNUNET_ARM_ResultMessage))
953 {
954 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
955 _("Failed to transmit shutdown ACK.\n"));
956 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
957 return 0; /* client disconnected */
958 }
1233 /* Make the connection flushing for the purpose of ACK transmitting, 959 /* Make the connection flushing for the purpose of ACK transmitting,
1234 * needed on W32 to ensure that the message is even received, harmless 960 * needed on W32 to ensure that the message is even received, harmless
1235 * on other platforms... */ 961 * on other platforms... */
1236 GNUNET_break (GNUNET_OK == GNUNET_SERVER_client_disable_corking (client)); 962 GNUNET_break (GNUNET_OK == GNUNET_SERVER_client_disable_corking (client));
1237 msg = (struct GNUNET_MessageHeader *) buf; 963 msg = (struct GNUNET_ARM_ResultMessage *) buf;
1238 msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN_ACK); 964 msg->header.type = htons (GNUNET_MESSAGE_TYPE_ARM_RESULT);
1239 msg->size = htons (sizeof (struct GNUNET_MessageHeader)); 965 msg->header.size = htons (sizeof (struct GNUNET_ARM_ResultMessage));
966 msg->status = htonl ((uint32_t) GNUNET_ARM_PROCESS_SHUTDOWN);
1240 GNUNET_SERVER_receive_done (client, GNUNET_OK); 967 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1241 GNUNET_SERVER_client_drop (client); 968 GNUNET_SERVER_client_drop (client);
1242 return sizeof (struct GNUNET_MessageHeader); 969 return sizeof (struct GNUNET_ARM_ResultMessage);
1243} 970}
1244 971
1245 972
@@ -1252,17 +979,15 @@ transmit_shutdown_ack (void *cls, size_t size, void *buf)
1252 */ 979 */
1253static void 980static void
1254handle_shutdown (void *cls, struct GNUNET_SERVER_Client *client, 981handle_shutdown (void *cls, struct GNUNET_SERVER_Client *client,
1255 const struct GNUNET_MessageHeader *message) 982 const struct GNUNET_MessageHeader *message)
1256{ 983{
984 GNUNET_SCHEDULER_shutdown ();
1257 GNUNET_SERVER_client_keep (client); 985 GNUNET_SERVER_client_keep (client);
1258 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1259 _("Initiating shutdown as requested by client.\n"));
1260 GNUNET_SERVER_notify_transmit_ready (client, 986 GNUNET_SERVER_notify_transmit_ready (client,
1261 sizeof (struct GNUNET_MessageHeader), 987 sizeof (struct GNUNET_ARM_ResultMessage),
1262 GNUNET_TIME_UNIT_FOREVER_REL, 988 GNUNET_TIME_UNIT_FOREVER_REL,
1263 &transmit_shutdown_ack, client); 989 &transmit_shutdown_ack, client);
1264 GNUNET_SERVER_client_persist_ (client); 990 GNUNET_SERVER_client_persist_ (client);
1265 GNUNET_SCHEDULER_shutdown ();
1266} 991}
1267 992
1268 993
@@ -1274,13 +999,77 @@ static void
1274sighandler_child_death () 999sighandler_child_death ()
1275{ 1000{
1276 static char c; 1001 static char c;
1277 int old_errno = errno; /* back-up errno */ 1002 int old_errno = errno; /* back-up errno */
1278 1003
1279 GNUNET_break (1 == 1004 GNUNET_break (1 ==
1280 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle 1005 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
1281 (sigpipe, GNUNET_DISK_PIPE_END_WRITE), 1006 (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
1282 &c, sizeof (c))); 1007 &c, sizeof (c)));
1283 errno = old_errno; /* restore errno */ 1008 errno = old_errno; /* restore errno */
1009}
1010
1011
1012/**
1013 * Setup our service record for the given section in the configuration file
1014 * (assuming the section is for a service).
1015 *
1016 * @param cls unused
1017 * @param section a section in the configuration file
1018 * @return GNUNET_OK (continue)
1019 */
1020static void
1021setup_service (void *cls, const char *section)
1022{
1023 struct ServiceList *sl;
1024 char *binary;
1025 char *config;
1026 struct stat sbuf;
1027 struct sockaddr **addrs;
1028 socklen_t *addr_lens;
1029 int ret;
1030 unsigned int i;
1031
1032 if (strcasecmp (section, "arm") == 0)
1033 return;
1034 if (GNUNET_OK !=
1035 GNUNET_CONFIGURATION_get_value_string (cfg, section, "BINARY", &binary))
1036 {
1037 /* not a service section */
1038 return;
1039 }
1040 config = NULL;
1041 if ((GNUNET_OK !=
1042 GNUNET_CONFIGURATION_get_value_filename (cfg, section, "CONFIG",
1043 &config)) ||
1044 (0 != STAT (config, &sbuf)))
1045 {
1046 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1047 _
1048 ("Configuration file `%s' for service `%s' not valid: %s\n"),
1049 config, section,
1050 (config == NULL) ? _("option missing") : STRERROR (errno));
1051 GNUNET_free (binary);
1052 GNUNET_free_non_null (config);
1053 return;
1054 }
1055 sl = GNUNET_malloc (sizeof (struct ServiceList));
1056 sl->name = GNUNET_strdup (section);
1057 sl->binary = binary;
1058 sl->config = config;
1059 sl->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
1060 sl->restart_at = GNUNET_TIME_UNIT_FOREVER_ABS;
1061 GNUNET_CONTAINER_DLL_insert (running_head, running_tail, sl);
1062 if (GNUNET_YES !=
1063 GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "AUTOSTART"))
1064 return;
1065 if (0 >= (ret = GNUNET_SERVICE_get_server_addresses (section, cfg,
1066 &addrs, &addr_lens)))
1067 return;
1068 /* this will free (or capture) addrs[i] */
1069 for (i = 0; i < ret; i++)
1070 create_listen_socket (addrs[i], addr_lens[i], sl);
1071 GNUNET_free (addrs);
1072 GNUNET_free (addr_lens);
1284} 1073}
1285 1074
1286 1075
@@ -1303,64 +1092,68 @@ run (void *cls, struct GNUNET_SERVER_Handle *serv,
1303 {NULL, NULL, 0, 0} 1092 {NULL, NULL, 0, 0}
1304 }; 1093 };
1305 char *defaultservices; 1094 char *defaultservices;
1306 char *pos; 1095 const char *pos;
1096 struct ServiceList *sl;
1307 1097
1308 cfg = c; 1098 cfg = c;
1309 server = serv; 1099 server = serv;
1310 GNUNET_assert (serv != NULL); 1100 GNUNET_assert (serv != NULL);
1311 pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
1312 GNUNET_assert (pr != NULL);
1313 GNUNET_SERVER_ignore_shutdown (serv, GNUNET_YES); 1101 GNUNET_SERVER_ignore_shutdown (serv, GNUNET_YES);
1314 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, 1102 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1315 NULL); 1103 NULL);
1316 child_death_task = 1104 child_death_task =
1317 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, pr, 1105 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1318 &maint_child_death, NULL); 1106 GNUNET_DISK_pipe_handle (sigpipe,
1107 GNUNET_DISK_PIPE_END_READ),
1108 &maint_child_death, NULL);
1319 1109
1320 if (GNUNET_OK != 1110 if (GNUNET_OK !=
1321 GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "GLOBAL_PREFIX", 1111 GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "GLOBAL_PREFIX",
1322 &prefix_command)) 1112 &prefix_command))
1323 prefix_command = GNUNET_strdup (""); 1113 prefix_command = GNUNET_strdup ("");
1324 if (GNUNET_OK != 1114 if (GNUNET_OK !=
1325 GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "GLOBAL_POSTFIX", 1115 GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "GLOBAL_POSTFIX",
1326 &final_option)) 1116 &final_option))
1327 final_option = GNUNET_strdup (""); 1117 final_option = GNUNET_strdup ("");
1118
1119 GNUNET_CONFIGURATION_iterate_sections (cfg, &setup_service, NULL);
1120
1328 /* start default services... */ 1121 /* start default services... */
1329 if (GNUNET_OK == 1122 if (GNUNET_OK ==
1330 GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "DEFAULTSERVICES", 1123 GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "DEFAULTSERVICES",
1331 &defaultservices)) 1124 &defaultservices))
1332 {
1333#if DEBUG_ARM
1334 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting default services `%s'\n",
1335 defaultservices);
1336#endif
1337 if (0 < strlen (defaultservices))
1338 { 1125 {
1339 pos = strtok (defaultservices, " "); 1126 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1340 while (pos != NULL) 1127 _("Starting default services `%s'\n"), defaultservices);
1341 { 1128 if (0 < strlen (defaultservices))
1342 start_service (NULL, pos, NULL); 1129 {
1343 pos = strtok (NULL, " "); 1130 for (pos = strtok (defaultservices, " "); NULL != pos;
1344 } 1131 pos = strtok (NULL, " "))
1132 {
1133 sl = find_service (pos);
1134 if (NULL == sl)
1135 {
1136 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1137 _
1138 ("Default service `%s' not configured correctly!\n"),
1139 pos);
1140 continue;
1141 }
1142 sl->is_default = GNUNET_YES;
1143 start_process (sl);
1144 }
1145 }
1146 GNUNET_free (defaultservices);
1345 } 1147 }
1346 GNUNET_free (defaultservices);
1347 }
1348 else 1148 else
1349 { 1149 {
1350#if DEBUG_ARM 1150 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No default services configured.\n"); 1151 _
1352#endif 1152 ("No default services configured, GNUnet will not really start right now.\n"));
1353 } 1153 }
1354
1355 /* create listening sockets for future services */
1356 prepare_services (cfg);
1357 1154
1358 /* process client requests */ 1155 /* process client requests */
1359 GNUNET_SERVER_add_handlers (server, handlers); 1156 GNUNET_SERVER_add_handlers (server, handlers);
1360
1361 /* manage services */
1362 GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
1363 &config_change_task, NULL);
1364} 1157}
1365 1158
1366 1159
@@ -1380,10 +1173,10 @@ main (int argc, char *const *argv)
1380 sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO); 1173 sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO);
1381 GNUNET_assert (sigpipe != NULL); 1174 GNUNET_assert (sigpipe != NULL);
1382 shc_chld = 1175 shc_chld =
1383 GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death); 1176 GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
1384 ret = 1177 ret =
1385 (GNUNET_OK == 1178 (GNUNET_OK ==
1386 GNUNET_SERVICE_run (argc, argv, "arm", GNUNET_YES, &run, NULL)) ? 0 : 1; 1179 GNUNET_SERVICE_run (argc, argv, "arm", GNUNET_YES, &run, NULL)) ? 0 : 1;
1387 GNUNET_SIGNAL_handler_uninstall (shc_chld); 1180 GNUNET_SIGNAL_handler_uninstall (shc_chld);
1388 shc_chld = NULL; 1181 shc_chld = NULL;
1389 GNUNET_DISK_pipe_close (sigpipe); 1182 GNUNET_DISK_pipe_close (sigpipe);
@@ -1391,6 +1184,7 @@ main (int argc, char *const *argv)
1391 return ret; 1184 return ret;
1392} 1185}
1393 1186
1187
1394#ifdef LINUX 1188#ifdef LINUX
1395#include <malloc.h> 1189#include <malloc.h>
1396 1190