aboutsummaryrefslogtreecommitdiff
path: root/src/arm
diff options
context:
space:
mode:
Diffstat (limited to 'src/arm')
-rw-r--r--src/arm/Makefile.am2
-rw-r--r--src/arm/arm.h19
-rw-r--r--src/arm/arm_api.c446
-rw-r--r--src/arm/do_start_process.c56
-rw-r--r--src/arm/gnunet-arm.c319
-rw-r--r--src/arm/gnunet-service-arm.c1466
-rw-r--r--src/arm/mockup-service.c2
-rw-r--r--src/arm/test_arm_api.c73
-rw-r--r--src/arm/test_exponential_backoff.c221
-rwxr-xr-xsrc/arm/test_gnunet_arm.sh39
-rw-r--r--src/arm/test_gnunet_service_manager.c103
11 files changed, 1247 insertions, 1499 deletions
diff --git a/src/arm/Makefile.am b/src/arm/Makefile.am
index 7d96ba594..2bc81653c 100644
--- a/src/arm/Makefile.am
+++ b/src/arm/Makefile.am
@@ -23,7 +23,7 @@ libgnunetarm_la_LIBADD = \
23 $(GN_LIBINTL) $(XLIB) 23 $(GN_LIBINTL) $(XLIB)
24libgnunetarm_la_LDFLAGS = \ 24libgnunetarm_la_LDFLAGS = \
25 $(GN_LIB_LDFLAGS) $(WINFLAGS) \ 25 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
26 -version-info 0:0:0 26 -version-info 1:0:0
27 27
28 28
29bin_PROGRAMS = \ 29bin_PROGRAMS = \
diff --git a/src/arm/arm.h b/src/arm/arm.h
index f20562c20..615079b7c 100644
--- a/src/arm/arm.h
+++ b/src/arm/arm.h
@@ -33,4 +33,23 @@
33 */ 33 */
34#define DEBUG_ARM GNUNET_EXTRA_LOGGING 34#define DEBUG_ARM GNUNET_EXTRA_LOGGING
35 35
36
37/**
38 * Reply from ARM to client.
39 */
40struct GNUNET_ARM_ResultMessage
41{
42
43 /**
44 * Reply to client, of type is GNUNET_MESSAGE_TYPE_ARM_RESULT.
45 */
46 struct GNUNET_MessageHeader header;
47
48 /**
49 * Status from the 'enum GNUNET_ARM_ProcessStatus'
50 */
51 uint32_t status;
52};
53
54
36#endif 55#endif
diff --git a/src/arm/arm_api.c b/src/arm/arm_api.c
index c15c59875..12395fea9 100644
--- a/src/arm/arm_api.c
+++ b/src/arm/arm_api.c
@@ -84,12 +84,13 @@ struct ShutdownContext
84 void *cont_cls; 84 void *cont_cls;
85 85
86 /** 86 /**
87 * We received a confirmation that the service will shut down. 87 * Result of the operation
88 */ 88 */
89 int confirmed; 89 enum GNUNET_ARM_ProcessStatus confirmed;
90 90
91}; 91};
92 92
93
93/** 94/**
94 * Handler receiving response to service shutdown requests. 95 * Handler receiving response to service shutdown requests.
95 * First call with NULL: service misbehaving, or something. 96 * First call with NULL: service misbehaving, or something.
@@ -105,76 +106,61 @@ static void
105service_shutdown_handler (void *cls, const struct GNUNET_MessageHeader *msg) 106service_shutdown_handler (void *cls, const struct GNUNET_MessageHeader *msg)
106{ 107{
107 struct ShutdownContext *shutdown_ctx = cls; 108 struct ShutdownContext *shutdown_ctx = cls;
109 const struct GNUNET_ARM_ResultMessage *rmsg;
108 110
109 if ((msg == NULL) && (shutdown_ctx->confirmed != GNUNET_YES)) 111 if (msg == NULL)
110 {
111#if DEBUG_ARM
112 /* Means the other side closed the connection and never confirmed a shutdown */
113 LOG (GNUNET_ERROR_TYPE_DEBUG, "Service handle shutdown before ACK!\n");
114#endif
115 if (shutdown_ctx->cont != NULL)
116 shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_SYSERR);
117 GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task);
118 GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO);
119 GNUNET_free (shutdown_ctx);
120 }
121 else if ((msg == NULL) && (shutdown_ctx->confirmed == GNUNET_YES))
122 { 112 {
123#if DEBUG_ARM
124 LOG (GNUNET_ERROR_TYPE_DEBUG, "Service shutdown complete.\n");
125#endif
126 if (shutdown_ctx->cont != NULL) 113 if (shutdown_ctx->cont != NULL)
127 shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_NO); 114 {
128 115 if (shutdown_ctx->confirmed == GNUNET_ARM_PROCESS_SHUTDOWN)
116 {
117 /* shutdown is now complete, as we waited for the network disconnect... */
118 shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_ARM_PROCESS_DOWN);
119 }
120 else
121 {
122 /* communication error */
123 shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR);
124 }
125 }
129 GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task); 126 GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task);
130 GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO); 127 GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO);
131 GNUNET_free (shutdown_ctx); 128 GNUNET_free (shutdown_ctx);
129 return;
132 } 130 }
133 else 131 if (ntohs (msg->size) ==
132 sizeof (struct GNUNET_ARM_ResultMessage))
134 { 133 {
135 GNUNET_assert (ntohs (msg->size) == sizeof (struct GNUNET_MessageHeader)); 134 rmsg = (const struct GNUNET_ARM_ResultMessage*) msg;
136 switch (ntohs (msg->type)) 135 shutdown_ctx->confirmed = (enum GNUNET_ARM_ProcessStatus) ntohl (rmsg->status);
136 if (shutdown_ctx->confirmed != GNUNET_ARM_PROCESS_SHUTDOWN)
137 { 137 {
138 case GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN_ACK: 138 /* ARM is not shutting down, well, report the error and be done with it... */
139#if DEBUG_ARM 139 shutdown_ctx->cont (shutdown_ctx->cont_cls, shutdown_ctx->confirmed);
140 LOG (GNUNET_ERROR_TYPE_DEBUG,
141 "Received confirmation for service shutdown.\n");
142#endif
143 shutdown_ctx->confirmed = GNUNET_YES;
144 GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler,
145 shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL);
146 break;
147 default:
148#if DEBUG_ARM
149 LOG (GNUNET_ERROR_TYPE_DEBUG, "Service shutdown refused!\n");
150#endif
151 if (shutdown_ctx->cont != NULL)
152 shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_YES);
153
154 GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task); 140 GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task);
155 GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO); 141 GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO);
156 GNUNET_free (shutdown_ctx); 142 GNUNET_free (shutdown_ctx);
157 break; 143 return;
158 } 144 }
159 } 145 }
146 GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler,
147 shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL);
160} 148}
161 149
150
162/** 151/**
163 * Shutting down took too long, cancel receive and return error. 152 * Shutting down took too long, cancel receive and return error.
164 * 153 *
165 * @param cls closure 154 * @param cls closure
166 * @param tc context information (why was this task triggered now) 155 * @param tc context information (why was this task triggered now)
167 */ 156 */
168void 157static void
169service_shutdown_cancel (void *cls, 158service_shutdown_cancel (void *cls,
170 const struct GNUNET_SCHEDULER_TaskContext *tc) 159 const struct GNUNET_SCHEDULER_TaskContext *tc)
171{ 160{
172 struct ShutdownContext *shutdown_ctx = cls; 161 struct ShutdownContext *shutdown_ctx = cls;
173 162
174#if DEBUG_ARM 163 shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_ARM_PROCESS_COMMUNICATION_TIMEOUT);
175 LOG (GNUNET_ERROR_TYPE_DEBUG, "service_shutdown_cancel called!\n");
176#endif
177 shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_SYSERR);
178 GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO); 164 GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO);
179 GNUNET_free (shutdown_ctx); 165 GNUNET_free (shutdown_ctx);
180} 166}
@@ -196,21 +182,21 @@ write_shutdown (void *cls, size_t size, void *buf)
196 struct ShutdownContext *shutdown_ctx = cls; 182 struct ShutdownContext *shutdown_ctx = cls;
197 183
198 if (size < sizeof (struct GNUNET_MessageHeader)) 184 if (size < sizeof (struct GNUNET_MessageHeader))
199 { 185 {
200 LOG (GNUNET_ERROR_TYPE_WARNING, 186 LOG (GNUNET_ERROR_TYPE_WARNING,
201 _("Failed to transmit shutdown request to client.\n")); 187 _("Failed to transmit shutdown request to client.\n"));
202 shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_SYSERR); 188 shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR);
203 GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO); 189 GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO);
204 GNUNET_free (shutdown_ctx); 190 GNUNET_free (shutdown_ctx);
205 return 0; /* client disconnected */ 191 return 0; /* client disconnected */
206 } 192 }
207 193
208 GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler, 194 GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler,
209 shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL); 195 shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL);
210 shutdown_ctx->cancel_task = 196 shutdown_ctx->cancel_task =
211 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining 197 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
212 (shutdown_ctx->timeout), 198 (shutdown_ctx->timeout),
213 &service_shutdown_cancel, shutdown_ctx); 199 &service_shutdown_cancel, shutdown_ctx);
214 msg = (struct GNUNET_MessageHeader *) buf; 200 msg = (struct GNUNET_MessageHeader *) buf;
215 msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN); 201 msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN);
216 msg->size = htons (sizeof (struct GNUNET_MessageHeader)); 202 msg->size = htons (sizeof (struct GNUNET_MessageHeader));
@@ -233,8 +219,8 @@ write_shutdown (void *cls, size_t size, void *buf)
233 */ 219 */
234static void 220static void
235arm_service_shutdown (struct GNUNET_CLIENT_Connection *sock, 221arm_service_shutdown (struct GNUNET_CLIENT_Connection *sock,
236 struct GNUNET_TIME_Relative timeout, 222 struct GNUNET_TIME_Relative timeout,
237 GNUNET_CLIENT_ShutdownTask cont, void *cont_cls) 223 GNUNET_CLIENT_ShutdownTask cont, void *cont_cls)
238{ 224{
239 struct ShutdownContext *shutdown_ctx; 225 struct ShutdownContext *shutdown_ctx;
240 226
@@ -243,10 +229,12 @@ arm_service_shutdown (struct GNUNET_CLIENT_Connection *sock,
243 shutdown_ctx->cont_cls = cont_cls; 229 shutdown_ctx->cont_cls = cont_cls;
244 shutdown_ctx->sock = sock; 230 shutdown_ctx->sock = sock;
245 shutdown_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); 231 shutdown_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
232 shutdown_ctx->confirmed = GNUNET_ARM_PROCESS_COMMUNICATION_ERROR;
233 /* FIXME: store return value? */
246 GNUNET_CLIENT_notify_transmit_ready (sock, 234 GNUNET_CLIENT_notify_transmit_ready (sock,
247 sizeof (struct GNUNET_MessageHeader), 235 sizeof (struct GNUNET_MessageHeader),
248 timeout, GNUNET_YES, &write_shutdown, 236 timeout, GNUNET_YES, &write_shutdown,
249 shutdown_ctx); 237 shutdown_ctx);
250} 238}
251 239
252 240
@@ -262,7 +250,7 @@ arm_service_shutdown (struct GNUNET_CLIENT_Connection *sock,
262 */ 250 */
263struct GNUNET_ARM_Handle * 251struct GNUNET_ARM_Handle *
264GNUNET_ARM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, 252GNUNET_ARM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
265 const char *service) 253 const char *service)
266{ 254{
267 struct GNUNET_ARM_Handle *ret; 255 struct GNUNET_ARM_Handle *ret;
268 256
@@ -286,6 +274,7 @@ GNUNET_ARM_disconnect (struct GNUNET_ARM_Handle *h)
286 GNUNET_free (h); 274 GNUNET_free (h);
287} 275}
288 276
277
289struct ARM_ShutdownContext 278struct ARM_ShutdownContext
290{ 279{
291 /** 280 /**
@@ -300,7 +289,6 @@ struct ARM_ShutdownContext
300}; 289};
301 290
302 291
303
304/** 292/**
305 * Internal state for a request with ARM. 293 * Internal state for a request with ARM.
306 */ 294 */
@@ -357,17 +345,17 @@ arm_service_report (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
357 char *lopostfix; 345 char *lopostfix;
358 346
359 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) 347 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE))
360 { 348 {
361#if DEBUG_ARM 349#if DEBUG_ARM
362 LOG (GNUNET_ERROR_TYPE_DEBUG, "Looks like `%s' is already running.\n", 350 LOG (GNUNET_ERROR_TYPE_DEBUG, "Looks like `%s' is already running.\n",
363 "gnunet-service-arm"); 351 "gnunet-service-arm");
364#endif 352#endif
365 /* arm is running! */ 353 /* arm is running! */
366 if (pos->callback != NULL) 354 if (pos->callback != NULL)
367 pos->callback (pos->cls, GNUNET_YES); 355 pos->callback (pos->cls, GNUNET_ARM_PROCESS_ALREADY_RUNNING);
368 GNUNET_free (pos); 356 GNUNET_free (pos);
369 return; 357 return;
370 } 358 }
371#if DEBUG_ARM 359#if DEBUG_ARM
372 LOG (GNUNET_ERROR_TYPE_DEBUG, 360 LOG (GNUNET_ERROR_TYPE_DEBUG,
373 "Looks like `%s' is not running, will start it.\n", 361 "Looks like `%s' is not running, will start it.\n",
@@ -375,73 +363,81 @@ arm_service_report (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
375#endif 363#endif
376 if (GNUNET_OK != 364 if (GNUNET_OK !=
377 GNUNET_CONFIGURATION_get_value_string (pos->h->cfg, "arm", "PREFIX", 365 GNUNET_CONFIGURATION_get_value_string (pos->h->cfg, "arm", "PREFIX",
378 &loprefix)) 366 &loprefix))
379 loprefix = GNUNET_strdup (""); 367 loprefix = GNUNET_strdup ("");
380 if (GNUNET_OK != 368 if (GNUNET_OK !=
381 GNUNET_CONFIGURATION_get_value_string (pos->h->cfg, "arm", "OPTIONS", 369 GNUNET_CONFIGURATION_get_value_string (pos->h->cfg, "arm", "OPTIONS",
382 &lopostfix)) 370 &lopostfix))
383 lopostfix = GNUNET_strdup (""); 371 lopostfix = GNUNET_strdup ("");
384 if (GNUNET_OK != 372 if (GNUNET_OK !=
385 GNUNET_CONFIGURATION_get_value_string (pos->h->cfg, "arm", "BINARY", 373 GNUNET_CONFIGURATION_get_value_string (pos->h->cfg, "arm", "BINARY",
386 &binary)) 374 &binary))
387 { 375 {
388 LOG (GNUNET_ERROR_TYPE_WARNING, 376 LOG (GNUNET_ERROR_TYPE_WARNING,
389 _("Configuration failes to specify option `%s' in section `%s'!\n"), 377 _
390 "BINARY", "arm"); 378 ("Configuration failes to specify option `%s' in section `%s'!\n"),
391 if (pos->callback != NULL) 379 "BINARY", "arm");
392 pos->callback (pos->cls, GNUNET_SYSERR); 380 if (pos->callback != NULL)
393 GNUNET_free (pos); 381 pos->callback (pos->cls, GNUNET_ARM_PROCESS_UNKNOWN);
394 GNUNET_free (loprefix); 382 GNUNET_free (pos);
395 GNUNET_free (lopostfix); 383 GNUNET_free (loprefix);
396 return; 384 GNUNET_free (lopostfix);
397 } 385 return;
386 }
398 if (GNUNET_OK != 387 if (GNUNET_OK !=
399 GNUNET_CONFIGURATION_get_value_filename (pos->h->cfg, "arm", "CONFIG", 388 GNUNET_CONFIGURATION_get_value_filename (pos->h->cfg, "arm", "CONFIG",
400 &config)) 389 &config))
401 { 390 {
402 LOG (GNUNET_ERROR_TYPE_WARNING, 391 LOG (GNUNET_ERROR_TYPE_WARNING,
403 _("Configuration fails to specify option `%s' in section `%s'!\n"), 392 _("Configuration fails to specify option `%s' in section `%s'!\n"),
404 "CONFIG", "arm"); 393 "CONFIG", "arm");
405 if (pos->callback != NULL) 394 if (pos->callback != NULL)
406 pos->callback (pos->cls, GNUNET_SYSERR); 395 pos->callback (pos->cls, GNUNET_ARM_PROCESS_UNKNOWN);
407 GNUNET_free (binary); 396 GNUNET_free (binary);
408 GNUNET_free (pos); 397 GNUNET_free (pos);
409 GNUNET_free (loprefix); 398 GNUNET_free (loprefix);
410 GNUNET_free (lopostfix); 399 GNUNET_free (lopostfix);
411 return; 400 return;
412 } 401 }
413 if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (pos->h->cfg, "TESTING", "WEAKRANDOM")) && (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (pos->h->cfg, "TESTING", "WEAKRANDOM")) && (GNUNET_NO == GNUNET_CONFIGURATION_have_value (pos->h->cfg, "TESTING", "HOSTFILE")) /* Means we are ONLY running locally */ 402 if ((GNUNET_YES ==
414 ) 403 GNUNET_CONFIGURATION_have_value (pos->h->cfg, "TESTING", "WEAKRANDOM"))
415 { 404 && (GNUNET_YES ==
416 /* we're clearly running a test, don't daemonize */ 405 GNUNET_CONFIGURATION_get_value_yesno (pos->h->cfg, "TESTING",
417 proc = do_start_process (NULL, loprefix, binary, "-c", config, 406 "WEAKRANDOM"))
407 && (GNUNET_NO ==
408 GNUNET_CONFIGURATION_have_value (pos->h->cfg, "TESTING",
409 "HOSTFILE")))
410 {
411 /* Means we are ONLY running locally */
412 /* we're clearly running a test, don't daemonize */
413 proc = do_start_process (NULL, loprefix, binary, "-c", config,
418#if DEBUG_ARM 414#if DEBUG_ARM
419 "-L", "DEBUG", 415 "-L", "DEBUG",
420#endif 416#endif
421 /* no daemonization! */ 417 /* no daemonization! */
422 lopostfix, NULL); 418 lopostfix, NULL);
423 } 419 }
424 else 420 else
425 { 421 {
426 proc = do_start_process (NULL, loprefix, binary, "-c", config, 422 proc = do_start_process (NULL, loprefix, binary, "-c", config,
427#if DEBUG_ARM 423#if DEBUG_ARM
428 "-L", "DEBUG", 424 "-L", "DEBUG",
429#endif 425#endif
430 "-d", lopostfix, NULL); 426 "-d", lopostfix, NULL);
431 } 427 }
432 GNUNET_free (binary); 428 GNUNET_free (binary);
433 GNUNET_free (config); 429 GNUNET_free (config);
434 GNUNET_free (loprefix); 430 GNUNET_free (loprefix);
435 GNUNET_free (lopostfix); 431 GNUNET_free (lopostfix);
436 if (proc == NULL) 432 if (proc == NULL)
437 { 433 {
438 if (pos->callback != NULL) 434 if (pos->callback != NULL)
439 pos->callback (pos->cls, GNUNET_SYSERR); 435 pos->callback (pos->cls, GNUNET_ARM_PROCESS_FAILURE);
440 GNUNET_free (pos); 436 GNUNET_free (pos);
441 return; 437 return;
442 } 438 }
443 if (pos->callback != NULL) 439 if (pos->callback != NULL)
444 pos->callback (pos->cls, GNUNET_YES); 440 pos->callback (pos->cls, GNUNET_ARM_PROCESS_STARTING);
445 GNUNET_free (proc); 441 GNUNET_free (proc);
446 GNUNET_free (pos); 442 GNUNET_free (pos);
447} 443}
@@ -458,45 +454,34 @@ static void
458handle_response (void *cls, const struct GNUNET_MessageHeader *msg) 454handle_response (void *cls, const struct GNUNET_MessageHeader *msg)
459{ 455{
460 struct RequestContext *sc = cls; 456 struct RequestContext *sc = cls;
461 int ret; 457 const struct GNUNET_ARM_ResultMessage *res;
458 enum GNUNET_ARM_ProcessStatus status;
462 459
463 if (msg == NULL) 460 if ((msg == NULL) ||
464 { 461 (ntohs (msg->size) != sizeof (struct GNUNET_ARM_ResultMessage)))
465 LOG (GNUNET_ERROR_TYPE_WARNING, 462 {
466 _ 463 LOG (GNUNET_ERROR_TYPE_WARNING,
467 ("Error receiving response to `%s' request from ARM for service `%s'\n"), 464 _
468 (sc->type == GNUNET_MESSAGE_TYPE_ARM_START) ? "START" : "STOP", 465 ("Error receiving response to `%s' request from ARM for service `%s'\n"),
469 (const char *) &sc[1]); 466 (sc->type == GNUNET_MESSAGE_TYPE_ARM_START) ? "START" : "STOP",
470 GNUNET_CLIENT_disconnect (sc->h->client, GNUNET_NO); 467 (const char *) &sc[1]);
471 sc->h->client = GNUNET_CLIENT_connect ("arm", sc->h->cfg); 468 GNUNET_CLIENT_disconnect (sc->h->client, GNUNET_NO);
472 GNUNET_assert (NULL != sc->h->client); 469 sc->h->client = GNUNET_CLIENT_connect ("arm", sc->h->cfg);
473 if (sc->callback != NULL) 470 GNUNET_assert (NULL != sc->h->client);
474 sc->callback (sc->cls, GNUNET_SYSERR); 471 if (sc->callback != NULL)
475 GNUNET_free (sc); 472 sc->callback (sc->cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR);
476 return; 473 GNUNET_free (sc);
477 } 474 return;
475 }
476 res = (const struct GNUNET_ARM_ResultMessage *) msg;
478#if DEBUG_ARM 477#if DEBUG_ARM
479 LOG (GNUNET_ERROR_TYPE_DEBUG, 478 LOG (GNUNET_ERROR_TYPE_DEBUG,
480 "Received response from ARM for service `%s': %u\n", 479 "Received response from ARM for service `%s': %u\n",
481 (const char *) &sc[1], ntohs (msg->type)); 480 (const char *) &sc[1], ntohs (msg->type));
482#endif 481#endif
483 switch (ntohs (msg->type)) 482 status = (enum GNUNET_ARM_ProcessStatus) ntohl (res->status);
484 {
485 case GNUNET_MESSAGE_TYPE_ARM_IS_UP:
486 ret = GNUNET_YES;
487 break;
488 case GNUNET_MESSAGE_TYPE_ARM_IS_DOWN:
489 ret = GNUNET_NO;
490 break;
491 case GNUNET_MESSAGE_TYPE_ARM_IS_UNKNOWN:
492 ret = GNUNET_SYSERR;
493 break;
494 default:
495 GNUNET_break (0);
496 ret = GNUNET_SYSERR;
497 }
498 if (sc->callback != NULL) 483 if (sc->callback != NULL)
499 sc->callback (sc->cls, ret); 484 sc->callback (sc->cls, status);
500 GNUNET_free (sc); 485 GNUNET_free (sc);
501} 486}
502 487
@@ -513,8 +498,8 @@ handle_response (void *cls, const struct GNUNET_MessageHeader *msg)
513 */ 498 */
514static void 499static void
515change_service (struct GNUNET_ARM_Handle *h, const char *service_name, 500change_service (struct GNUNET_ARM_Handle *h, const char *service_name,
516 struct GNUNET_TIME_Relative timeout, GNUNET_ARM_Callback cb, 501 struct GNUNET_TIME_Relative timeout, GNUNET_ARM_Callback cb,
517 void *cb_cls, uint16_t type) 502 void *cb_cls, uint16_t type)
518{ 503{
519 struct RequestContext *sctx; 504 struct RequestContext *sctx;
520 size_t slen; 505 size_t slen;
@@ -523,16 +508,16 @@ change_service (struct GNUNET_ARM_Handle *h, const char *service_name,
523 slen = strlen (service_name) + 1; 508 slen = strlen (service_name) + 1;
524 if (slen + sizeof (struct GNUNET_MessageHeader) >= 509 if (slen + sizeof (struct GNUNET_MessageHeader) >=
525 GNUNET_SERVER_MAX_MESSAGE_SIZE) 510 GNUNET_SERVER_MAX_MESSAGE_SIZE)
526 { 511 {
527 GNUNET_break (0); 512 GNUNET_break (0);
528 if (cb != NULL) 513 if (cb != NULL)
529 cb (cb_cls, GNUNET_NO); 514 cb (cb_cls, GNUNET_NO);
530 return; 515 return;
531 } 516 }
532#if DEBUG_ARM 517#if DEBUG_ARM
533 LOG (GNUNET_ERROR_TYPE_DEBUG, 518 LOG (GNUNET_ERROR_TYPE_DEBUG,
534 (type == 519 (type ==
535 GNUNET_MESSAGE_TYPE_ARM_START) ? 520 GNUNET_MESSAGE_TYPE_ARM_START) ?
536 _("Requesting start of service `%s'.\n") : 521 _("Requesting start of service `%s'.\n") :
537 _("Requesting termination of service `%s'.\n"), service_name); 522 _("Requesting termination of service `%s'.\n"), service_name);
538#endif 523#endif
@@ -549,22 +534,23 @@ change_service (struct GNUNET_ARM_Handle *h, const char *service_name,
549 memcpy (&msg[1], service_name, slen); 534 memcpy (&msg[1], service_name, slen);
550 if (GNUNET_OK != 535 if (GNUNET_OK !=
551 GNUNET_CLIENT_transmit_and_get_response (sctx->h->client, msg, 536 GNUNET_CLIENT_transmit_and_get_response (sctx->h->client, msg,
552 GNUNET_TIME_absolute_get_remaining 537 GNUNET_TIME_absolute_get_remaining
553 (sctx->timeout), GNUNET_YES, 538 (sctx->timeout), GNUNET_YES,
554 &handle_response, sctx)) 539 &handle_response, sctx))
555 { 540 {
556 LOG (GNUNET_ERROR_TYPE_WARNING, 541 LOG (GNUNET_ERROR_TYPE_WARNING,
557 (type == 542 (type ==
558 GNUNET_MESSAGE_TYPE_ARM_START) ? 543 GNUNET_MESSAGE_TYPE_ARM_START) ?
559 _("Error while trying to transmit request to start `%s' to ARM\n") : 544 _("Error while trying to transmit request to start `%s' to ARM\n")
560 _("Error while trying to transmit request to stop `%s' to ARM\n"), 545 :
561 (const char *) &service_name); 546 _("Error while trying to transmit request to stop `%s' to ARM\n"),
562 if (cb != NULL) 547 (const char *) &service_name);
563 cb (cb_cls, GNUNET_SYSERR); 548 if (cb != NULL)
564 GNUNET_free (sctx); 549 cb (cb_cls, GNUNET_SYSERR);
565 GNUNET_free (msg); 550 GNUNET_free (sctx);
566 return; 551 GNUNET_free (msg);
567 } 552 return;
553 }
568 GNUNET_free (msg); 554 GNUNET_free (msg);
569} 555}
570 556
@@ -579,9 +565,10 @@ change_service (struct GNUNET_ARM_Handle *h, const char *service_name,
579 * @param cb_cls closure for callback 565 * @param cb_cls closure for callback
580 */ 566 */
581void 567void
582GNUNET_ARM_start_service (struct GNUNET_ARM_Handle *h, const char *service_name, 568GNUNET_ARM_start_service (struct GNUNET_ARM_Handle *h,
583 struct GNUNET_TIME_Relative timeout, 569 const char *service_name,
584 GNUNET_ARM_Callback cb, void *cb_cls) 570 struct GNUNET_TIME_Relative timeout,
571 GNUNET_ARM_Callback cb, void *cb_cls)
585{ 572{
586 struct RequestContext *sctx; 573 struct RequestContext *sctx;
587 struct GNUNET_CLIENT_Connection *client; 574 struct GNUNET_CLIENT_Connection *client;
@@ -593,47 +580,47 @@ GNUNET_ARM_start_service (struct GNUNET_ARM_Handle *h, const char *service_name,
593 (unsigned long long) timeout.rel_value); 580 (unsigned long long) timeout.rel_value);
594#endif 581#endif
595 if (0 == strcasecmp ("arm", service_name)) 582 if (0 == strcasecmp ("arm", service_name))
596 { 583 {
597 slen = strlen ("arm") + 1; 584 slen = strlen ("arm") + 1;
598 sctx = GNUNET_malloc (sizeof (struct RequestContext) + slen); 585 sctx = GNUNET_malloc (sizeof (struct RequestContext) + slen);
599 sctx->h = h; 586 sctx->h = h;
600 sctx->callback = cb; 587 sctx->callback = cb;
601 sctx->cls = cb_cls; 588 sctx->cls = cb_cls;
602 sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); 589 sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
603 memcpy (&sctx[1], service_name, slen); 590 memcpy (&sctx[1], service_name, slen);
604 GNUNET_CLIENT_service_test ("arm", h->cfg, timeout, &arm_service_report, 591 GNUNET_CLIENT_service_test ("arm", h->cfg, timeout, &arm_service_report,
605 sctx); 592 sctx);
606 return; 593 return;
607 } 594 }
608 if (h->client == NULL) 595 if (h->client == NULL)
609 {
610 client = GNUNET_CLIENT_connect ("arm", h->cfg);
611 if (client == NULL)
612 { 596 {
597 client = GNUNET_CLIENT_connect ("arm", h->cfg);
598 if (client == NULL)
599 {
600 LOG (GNUNET_ERROR_TYPE_DEBUG,
601 "arm_api, GNUNET_CLIENT_connect returned NULL\n");
602 cb (cb_cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR);
603 return;
604 }
613 LOG (GNUNET_ERROR_TYPE_DEBUG, 605 LOG (GNUNET_ERROR_TYPE_DEBUG,
614 "arm_api, GNUNET_CLIENT_connect returned NULL\n"); 606 "arm_api, GNUNET_CLIENT_connect returned non-NULL\n");
615 cb (cb_cls, GNUNET_SYSERR); 607 h->client = client;
616 return;
617 } 608 }
618 LOG (GNUNET_ERROR_TYPE_DEBUG,
619 "arm_api, GNUNET_CLIENT_connect returned non-NULL\n");
620 h->client = client;
621 }
622 LOG (GNUNET_ERROR_TYPE_DEBUG, "arm_api, h->client non-NULL\n"); 609 LOG (GNUNET_ERROR_TYPE_DEBUG, "arm_api, h->client non-NULL\n");
623 change_service (h, service_name, timeout, cb, cb_cls, 610 change_service (h, service_name, timeout, cb, cb_cls,
624 GNUNET_MESSAGE_TYPE_ARM_START); 611 GNUNET_MESSAGE_TYPE_ARM_START);
625} 612}
626 613
614
627/** 615/**
628 * Callback from the arm stop service call, indicates that the arm service 616 * Callback from the arm stop service call, indicates that the arm service
629 * is well and truly dead, won't die, or an error occurred. 617 * is well and truly dead, won't die, or an error occurred.
630 * 618 *
631 * @param cls closure for the callback 619 * @param cls closure for the callback
632 * @param reason reason for callback, GNUNET_NO if arm is shutdown 620 * @param reason reason for callback
633 * GNUNET_YES if arm remains running, and GNUNET_SYSERR on error
634 */ 621 */
635void 622static void
636arm_shutdown_callback (void *cls, int reason) 623arm_shutdown_callback (void *cls, enum GNUNET_ARM_ProcessStatus reason)
637{ 624{
638 struct ARM_ShutdownContext *arm_shutdown_ctx = cls; 625 struct ARM_ShutdownContext *arm_shutdown_ctx = cls;
639 626
@@ -654,9 +641,10 @@ arm_shutdown_callback (void *cls, int reason)
654 * @param cb_cls closure for callback 641 * @param cb_cls closure for callback
655 */ 642 */
656void 643void
657GNUNET_ARM_stop_service (struct GNUNET_ARM_Handle *h, const char *service_name, 644GNUNET_ARM_stop_service (struct GNUNET_ARM_Handle *h,
658 struct GNUNET_TIME_Relative timeout, 645 const char *service_name,
659 GNUNET_ARM_Callback cb, void *cb_cls) 646 struct GNUNET_TIME_Relative timeout,
647 GNUNET_ARM_Callback cb, void *cb_cls)
660{ 648{
661 struct ARM_ShutdownContext *arm_shutdown_ctx; 649 struct ARM_ShutdownContext *arm_shutdown_ctx;
662 struct GNUNET_CLIENT_Connection *client; 650 struct GNUNET_CLIENT_Connection *client;
@@ -664,27 +652,27 @@ GNUNET_ARM_stop_service (struct GNUNET_ARM_Handle *h, const char *service_name,
664 LOG (GNUNET_ERROR_TYPE_INFO, _("Stopping service `%s' within %llu ms\n"), 652 LOG (GNUNET_ERROR_TYPE_INFO, _("Stopping service `%s' within %llu ms\n"),
665 service_name, (unsigned long long) timeout.rel_value); 653 service_name, (unsigned long long) timeout.rel_value);
666 if (h->client == NULL) 654 if (h->client == NULL)
667 {
668 client = GNUNET_CLIENT_connect ("arm", h->cfg);
669 if (client == NULL)
670 { 655 {
671 cb (cb_cls, GNUNET_SYSERR); 656 client = GNUNET_CLIENT_connect ("arm", h->cfg);
672 return; 657 if (client == NULL)
658 {
659 cb (cb_cls, GNUNET_SYSERR);
660 return;
661 }
662 h->client = client;
673 } 663 }
674 h->client = client;
675 }
676 if (0 == strcasecmp ("arm", service_name)) 664 if (0 == strcasecmp ("arm", service_name))
677 { 665 {
678 arm_shutdown_ctx = GNUNET_malloc (sizeof (struct ARM_ShutdownContext)); 666 arm_shutdown_ctx = GNUNET_malloc (sizeof (struct ARM_ShutdownContext));
679 arm_shutdown_ctx->cb = cb; 667 arm_shutdown_ctx->cb = cb;
680 arm_shutdown_ctx->cb_cls = cb_cls; 668 arm_shutdown_ctx->cb_cls = cb_cls;
681 arm_service_shutdown (h->client, timeout, &arm_shutdown_callback, 669 arm_service_shutdown (h->client, timeout, &arm_shutdown_callback,
682 arm_shutdown_ctx); 670 arm_shutdown_ctx);
683 h->client = NULL; 671 h->client = NULL;
684 return; 672 return;
685 } 673 }
686 change_service (h, service_name, timeout, cb, cb_cls, 674 change_service (h, service_name, timeout, cb, cb_cls,
687 GNUNET_MESSAGE_TYPE_ARM_STOP); 675 GNUNET_MESSAGE_TYPE_ARM_STOP);
688} 676}
689 677
690 678
diff --git a/src/arm/do_start_process.c b/src/arm/do_start_process.c
index f4d3424ff..fd7fc17ed 100644
--- a/src/arm/do_start_process.c
+++ b/src/arm/do_start_process.c
@@ -10,10 +10,10 @@
10 * @param lsocks array of listen sockets to dup starting at fd3 (systemd-style), or NULL 10 * @param lsocks array of listen sockets to dup starting at fd3 (systemd-style), or NULL
11 * @param first_arg first argument for argv (may be an empty string) 11 * @param first_arg first argument for argv (may be an empty string)
12 * @param ... more arguments, NULL terminated 12 * @param ... more arguments, NULL terminated
13 * @return PID of the started process, -1 on error 13 * @return handle of the started process, NULL on error
14 */ 14 */
15static struct GNUNET_OS_Process * 15static struct GNUNET_OS_Process *
16do_start_process (const SOCKTYPE *lsocks, const char *first_arg, ...) 16do_start_process (const SOCKTYPE * lsocks, const char *first_arg, ...)
17{ 17{
18 va_list ap; 18 va_list ap;
19 char **argv; 19 char **argv;
@@ -35,20 +35,20 @@ do_start_process (const SOCKTYPE *lsocks, const char *first_arg, ...)
35/* *INDENT-ON* */ 35/* *INDENT-ON* */
36 rpos = arg; 36 rpos = arg;
37 while ('\0' != *rpos) 37 while ('\0' != *rpos)
38 {
39 if (' ' == *rpos)
40 { 38 {
41 if (last != NULL) 39 if (' ' == *rpos)
42 argv_size++; 40 {
43 last = NULL; 41 if (last != NULL)
44 while (' ' == *rpos) 42 argv_size++;
45 rpos++; 43 last = NULL;
44 while (' ' == *rpos)
45 rpos++;
46 }
47 if ((last == NULL) && (*rpos != '\0'))
48 last = rpos;
49 if (*rpos != '\0')
50 rpos++;
46 } 51 }
47 if ((last == NULL) && (*rpos != '\0'))
48 last = rpos;
49 if (*rpos != '\0')
50 rpos++;
51 }
52 if (last != NULL) 52 if (last != NULL)
53 argv_size++; 53 argv_size++;
54/* *INDENT-OFF* */ 54/* *INDENT-OFF* */
@@ -69,22 +69,22 @@ do_start_process (const SOCKTYPE *lsocks, const char *first_arg, ...)
69 cp = GNUNET_strdup (arg); 69 cp = GNUNET_strdup (arg);
70 pos = cp; 70 pos = cp;
71 while ('\0' != *pos) 71 while ('\0' != *pos)
72 {
73 if (' ' == *pos)
74 { 72 {
75 *pos = '\0'; 73 if (' ' == *pos)
76 if (last != NULL) 74 {
77 argv[argv_size++] = GNUNET_strdup (last); 75 *pos = '\0';
78 last = NULL; 76 if (last != NULL)
79 pos++; 77 argv[argv_size++] = GNUNET_strdup (last);
80 while (' ' == *pos) 78 last = NULL;
81 pos++; 79 pos++;
80 while (' ' == *pos)
81 pos++;
82 }
83 if ((last == NULL) && (*pos != '\0'))
84 last = pos;
85 if (*pos != '\0')
86 pos++;
82 } 87 }
83 if ((last == NULL) && (*pos != '\0'))
84 last = pos;
85 if (*pos != '\0')
86 pos++;
87 }
88 if (last != NULL) 88 if (last != NULL)
89 argv[argv_size++] = GNUNET_strdup (last); 89 argv[argv_size++] = GNUNET_strdup (last);
90 last = NULL; 90 last = NULL;
diff --git a/src/arm/gnunet-arm.c b/src/arm/gnunet-arm.c
index db5687dbc..13b1fdc17 100644
--- a/src/arm/gnunet-arm.c
+++ b/src/arm/gnunet-arm.c
@@ -49,13 +49,6 @@
49#define START_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) 49#define START_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
50 50
51/** 51/**
52 * Timeout for starting services, very short because of the strange way start works
53 * (by checking if running before starting, so really this time is always waited on
54 * startup (annoying)).
55 */
56#define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2)
57
58/**
59 * Set if we are to shutdown all services (including ARM). 52 * Set if we are to shutdown all services (including ARM).
60 */ 53 */
61static int end; 54static int end;
@@ -91,11 +84,6 @@ static char *init;
91static char *term; 84static char *term;
92 85
93/** 86/**
94 * Set to the name of a service to test.
95 */
96static char *test;
97
98/**
99 * Set to the name of the config file used. 87 * Set to the name of the config file used.
100 */ 88 */
101static const char *config_file; 89static const char *config_file;
@@ -118,7 +106,7 @@ static struct GNUNET_ARM_Handle *h;
118/** 106/**
119 * Our configuration. 107 * Our configuration.
120 */ 108 */
121const struct GNUNET_CONFIGURATION_Handle *cfg; 109static const struct GNUNET_CONFIGURATION_Handle *cfg;
122 110
123/** 111/**
124 * Processing stage that we are in. Simple counter. 112 * Processing stage that we are in. Simple counter.
@@ -147,72 +135,62 @@ cps_loop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
147 * user and then runs the next phase in the FSM. 135 * user and then runs the next phase in the FSM.
148 * 136 *
149 * @param cls pointer to "const char*" identifying service that was manipulated 137 * @param cls pointer to "const char*" identifying service that was manipulated
150 * @param success GNUNET_OK if service is now running, GNUNET_NO if not, GNUNET_SYSERR on error 138 * @param result result of the operation
151 */ 139 */
152static void 140static void
153confirm_cb (void *cls, int success) 141confirm_cb (void *cls,
142 enum GNUNET_ARM_ProcessStatus result)
154{ 143{
155 const char *service = cls; 144 const char *service = cls;
156 145
157 switch (success) 146 switch (result)
158 { 147 {
159 case GNUNET_OK: 148 case GNUNET_ARM_PROCESS_UNKNOWN:
160 if (quiet != GNUNET_YES) 149 fprintf (stderr, _("Service `%s' is unknown to ARM.\n"), service);
161 fprintf (stdout, _("Service `%s' has been started.\n"), service); 150 ret = 1;
162 if ((phase - 1 != 2) && (phase - 1 != 3))
163 {
164 if (quiet != GNUNET_YES)
165 fprintf (stdout, _("Failed to stop service `%s'!\n"), service);
166 ret = 1;
167 }
168 break; 151 break;
169 case GNUNET_NO: 152 case GNUNET_ARM_PROCESS_DOWN:
170 if (quiet != GNUNET_YES) 153 if (quiet != GNUNET_YES)
171 fprintf (stdout, _("Service `%s' has been stopped.\n"), service); 154 fprintf (stdout, _("Service `%s' has been stopped.\n"), service);
172 if ((phase - 1 != 0) && (phase - 1 != 1))
173 {
174 if (quiet != GNUNET_YES)
175 fprintf (stdout, _("Failed to start service `%s'!\n"), service);
176 ret = 1;
177 }
178 break; 155 break;
179 case GNUNET_SYSERR: 156 case GNUNET_ARM_PROCESS_ALREADY_RUNNING:
180 if (quiet != GNUNET_YES) 157 fprintf (stderr, _("Service `%s' was already running.\n"), service);
181 fprintf (stdout, _("Some error communicating with service `%s'.\n"),
182 service);
183 ret = 1; 158 ret = 1;
184 break; 159 break;
185 } 160 case GNUNET_ARM_PROCESS_STARTING:
186
187 GNUNET_SCHEDULER_add_continuation (&cps_loop, NULL,
188 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
189}
190
191
192/**
193 * Function called to confirm that a service is running (or that
194 * it is not running).
195 *
196 * @param cls pointer to "const char*" identifying service that was manipulated
197 * @param tc reason determines if service is now running
198 */
199static void
200confirm_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
201{
202 const char *service = cls;
203
204 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE))
205 {
206 if (quiet != GNUNET_YES)
207 fprintf (stdout, _("Service `%s' is running.\n"), service);
208 }
209 else
210 {
211 if (quiet != GNUNET_YES) 161 if (quiet != GNUNET_YES)
212 fprintf (stdout, _("Service `%s' is not running.\n"), service); 162 fprintf (stdout, _("Service `%s' has been started.\n"), service);
163 break;
164 case GNUNET_ARM_PROCESS_ALREADY_STOPPING:
165 fprintf (stderr, _("Service `%s' was already being stopped.\n"), service);
166 ret = 1;
167 break;
168 case GNUNET_ARM_PROCESS_ALREADY_DOWN:
169 fprintf (stderr, _("Service `%s' was already not running.\n"), service);
170 ret = 1;
171 break;
172 case GNUNET_ARM_PROCESS_SHUTDOWN:
173 fprintf (stderr, _("Request ignored as ARM is shutting down.\n"));
174 ret = 1;
175 break;
176 case GNUNET_ARM_PROCESS_COMMUNICATION_ERROR:
177 fprintf (stderr, _("Error communicating with ARM service.\n"));
178 ret = 1;
179 break;
180 case GNUNET_ARM_PROCESS_COMMUNICATION_TIMEOUT:
181 fprintf (stderr, _("Timeout communicating with ARM service.\n"));
182 ret = 1;
183 break;
184 case GNUNET_ARM_PROCESS_FAILURE:
185 fprintf (stderr, _("Operation failed.\n"));
186 ret = 1;
187 break;
188 default:
189 fprintf (stderr, _("Unknown response code from ARM.\n"));
190 break;
213 } 191 }
214 GNUNET_SCHEDULER_add_continuation (&cps_loop, NULL, 192 GNUNET_SCHEDULER_add_continuation (&cps_loop, NULL,
215 GNUNET_SCHEDULER_REASON_PREREQ_DONE); 193 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
216} 194}
217 195
218 196
@@ -230,25 +208,25 @@ run (void *cls, char *const *args, const char *cfgfile,
230{ 208{
231 cfg = c; 209 cfg = c;
232 config_file = cfgfile; 210 config_file = cfgfile;
233 if (GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", "SERVICEHOME", &dir) 211 if (GNUNET_CONFIGURATION_get_value_string
234 != GNUNET_OK) 212 (cfg, "PATHS", "SERVICEHOME", &dir) != GNUNET_OK)
235 { 213 {
236 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 214 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
237 _ 215 _
238 ("Fatal configuration error: `%s' option in section `%s' missing.\n"), 216 ("Fatal configuration error: `%s' option in section `%s' missing.\n"),
239 "SERVICEHOME", "PATHS"); 217 "SERVICEHOME", "PATHS");
240 return; 218 return;
241 } 219 }
242 h = GNUNET_ARM_connect (cfg, NULL); 220 h = GNUNET_ARM_connect (cfg, NULL);
243 if (h == NULL) 221 if (h == NULL)
244 { 222 {
245 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 223 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
246 _("Fatal error initializing ARM API.\n")); 224 _("Fatal error initializing ARM API.\n"));
247 ret = 1; 225 ret = 1;
248 return; 226 return;
249 } 227 }
250 GNUNET_SCHEDULER_add_continuation (&cps_loop, NULL, 228 GNUNET_SCHEDULER_add_continuation (&cps_loop, NULL,
251 GNUNET_SCHEDULER_REASON_PREREQ_DONE); 229 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
252} 230}
253 231
254/** 232/**
@@ -260,21 +238,21 @@ static void
260delete_files () 238delete_files ()
261{ 239{
262 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 240 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
263 "Will attempt to remove configuration file %s and service directory %s\n", 241 "Will attempt to remove configuration file %s and service directory %s\n",
264 config_file, dir); 242 config_file, dir);
265 243
266 if (UNLINK (config_file) != 0) 244 if (UNLINK (config_file) != 0)
267 { 245 {
268 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 246 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
269 _("Failed to remove configuration file %s\n"), config_file); 247 _("Failed to remove configuration file %s\n"), config_file);
270 } 248 }
271 249
272 if (GNUNET_DISK_directory_remove (dir) != GNUNET_OK) 250 if (GNUNET_DISK_directory_remove (dir) != GNUNET_OK)
273 { 251 {
274 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 252 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
275 _("Failed to remove servicehome directory %s\n"), dir); 253 _("Failed to remove servicehome directory %s\n"), dir);
276 254
277 } 255 }
278} 256}
279 257
280/** 258/**
@@ -288,86 +266,76 @@ static void
288cps_loop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 266cps_loop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
289{ 267{
290 while (1) 268 while (1)
291 {
292 switch (phase++)
293 { 269 {
294 case 0: 270 switch (phase++)
295 if (term != NULL) 271 {
296 { 272 case 0:
297 GNUNET_ARM_stop_service (h, term, 273 if (term != NULL)
298 (0 == 274 {
299 timeout.rel_value) ? STOP_TIMEOUT : timeout, 275 GNUNET_ARM_stop_service (h, term,
300 &confirm_cb, term); 276 (0 ==
301 return; 277 timeout.rel_value) ? STOP_TIMEOUT :
302 } 278 timeout, &confirm_cb, term);
303 break; 279 return;
304 case 1: 280 }
305 if ((end) || (restart)) 281 break;
306 { 282 case 1:
307 GNUNET_ARM_stop_service (h, "arm", 283 if ((end) || (restart))
308 (0 == 284 {
309 timeout.rel_value) ? STOP_TIMEOUT_ARM : 285 GNUNET_ARM_stop_service (h, "arm",
310 timeout, &confirm_cb, "arm"); 286 (0 ==
311 return; 287 timeout.rel_value) ? STOP_TIMEOUT_ARM
312 } 288 : timeout, &confirm_cb, "arm");
313 break; 289 return;
314 case 2: 290 }
315 if (start) 291 break;
316 { 292 case 2:
317 GNUNET_ARM_start_service (h, "arm", 293 if (start)
318 (0 == 294 {
319 timeout.rel_value) ? START_TIMEOUT : timeout, 295 GNUNET_ARM_start_service (h, "arm",
320 &confirm_cb, "arm"); 296 (0 ==
321 return; 297 timeout.rel_value) ? START_TIMEOUT :
322 } 298 timeout, &confirm_cb, "arm");
323 break; 299 return;
324 case 3: 300 }
325 if (init != NULL) 301 break;
326 { 302 case 3:
327 GNUNET_ARM_start_service (h, init, 303 if (init != NULL)
328 (0 == 304 {
329 timeout.rel_value) ? START_TIMEOUT : timeout, 305 GNUNET_ARM_start_service (h, init,
330 &confirm_cb, init); 306 (0 ==
331 return; 307 timeout.rel_value) ? START_TIMEOUT :
332 } 308 timeout, &confirm_cb, init);
333 break; 309 return;
334 case 4: 310 }
335 if (test != NULL) 311 break;
336 { 312 case 4:
337 GNUNET_CLIENT_service_test (test, cfg, 313 if (restart)
338 (0 == 314 {
339 timeout.rel_value) ? TEST_TIMEOUT : 315 GNUNET_ARM_disconnect (h);
340 timeout, &confirm_task, test); 316 phase = 0;
341 return; 317 end = 0;
342 } 318 start = 1;
343 break; 319 restart = 0;
344 case 5: 320 h = GNUNET_ARM_connect (cfg, NULL);
345 if (restart) 321 if (h == NULL)
346 { 322 {
347 GNUNET_ARM_disconnect (h); 323 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
348 phase = 0; 324 _("Fatal error initializing ARM API.\n"));
349 end = 0; 325 ret = 1;
350 start = 1; 326 return;
351 restart = 0; 327 }
352 h = GNUNET_ARM_connect (cfg, NULL); 328 GNUNET_SCHEDULER_add_now (&cps_loop, NULL);
353 if (h == NULL) 329 return;
354 { 330 }
355 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 331 /* Fall through */
356 _("Fatal error initializing ARM API.\n")); 332 default: /* last phase */
357 ret = 1; 333 GNUNET_ARM_disconnect (h);
358 return; 334 if ((end == GNUNET_YES) && (delete == GNUNET_YES))
359 } 335 delete_files ();
360 GNUNET_SCHEDULER_add_now (&cps_loop, NULL); 336 return;
361 return; 337 }
362 }
363 /* Fall through */
364 default: /* last phase */
365 GNUNET_ARM_disconnect (h);
366 if ((end == GNUNET_YES) && (delete == GNUNET_YES))
367 delete_files ();
368 return;
369 } 338 }
370 }
371} 339}
372 340
373 341
@@ -395,9 +363,6 @@ main (int argc, char *const *argv)
395 {'r', "restart", NULL, 363 {'r', "restart", NULL,
396 gettext_noop ("stop and start all GNUnet default services"), 364 gettext_noop ("stop and start all GNUnet default services"),
397 GNUNET_NO, &GNUNET_GETOPT_set_one, &restart}, 365 GNUNET_NO, &GNUNET_GETOPT_set_one, &restart},
398 {'t', "test", "SERVICE",
399 gettext_noop ("test if a particular service is running"),
400 GNUNET_YES, &GNUNET_GETOPT_set_string, &test},
401 {'d', "delete", NULL, 366 {'d', "delete", NULL,
402 gettext_noop ("delete config file and directory on exit"), 367 gettext_noop ("delete config file and directory on exit"),
403 GNUNET_NO, &GNUNET_GETOPT_set_one, &delete}, 368 GNUNET_NO, &GNUNET_GETOPT_set_one, &delete},
@@ -414,12 +379,12 @@ main (int argc, char *const *argv)
414 379
415 if (GNUNET_OK == 380 if (GNUNET_OK ==
416 GNUNET_PROGRAM_run (argc, argv, "gnunet-arm", 381 GNUNET_PROGRAM_run (argc, argv, "gnunet-arm",
417 gettext_noop 382 gettext_noop
418 ("Control services and the Automated Restart Manager (ARM)"), 383 ("Control services and the Automated Restart Manager (ARM)"),
419 options, &run, NULL)) 384 options, &run, NULL))
420 { 385 {
421 return ret; 386 return ret;
422 } 387 }
423 388
424 return 1; 389 return 1;
425} 390}
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
diff --git a/src/arm/mockup-service.c b/src/arm/mockup-service.c
index 53a502fa8..1e9748809 100644
--- a/src/arm/mockup-service.c
+++ b/src/arm/mockup-service.c
@@ -46,7 +46,7 @@ transmit_shutdown_ack (void *cls, size_t size, void *buf)
46 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transmitting shutdown ACK.\n")); 46 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transmitting shutdown ACK.\n"));
47 47
48 msg = (struct GNUNET_MessageHeader *) buf; 48 msg = (struct GNUNET_MessageHeader *) buf;
49 msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN_ACK); 49 msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN);
50 msg->size = htons (sizeof (struct GNUNET_MessageHeader)); 50 msg->size = htons (sizeof (struct GNUNET_MessageHeader));
51 GNUNET_SERVER_receive_done (client, GNUNET_OK); 51 GNUNET_SERVER_receive_done (client, GNUNET_OK);
52 GNUNET_SERVER_client_drop (client); 52 GNUNET_SERVER_client_drop (client);
diff --git a/src/arm/test_arm_api.c b/src/arm/test_arm_api.c
index 5fbbaa6b1..74e225809 100644
--- a/src/arm/test_arm_api.c
+++ b/src/arm/test_arm_api.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors) 3 (C) 2009, 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
@@ -45,18 +45,20 @@ static struct GNUNET_ARM_Handle *arm;
45static int ok = 1; 45static int ok = 1;
46 46
47static void 47static void
48arm_stopped (void *cls, int success) 48arm_stopped (void *cls, enum GNUNET_ARM_ProcessStatus success)
49{ 49{
50 if (success != GNUNET_NO) 50 GNUNET_break (success == GNUNET_ARM_PROCESS_DOWN);
51 if (success != GNUNET_ARM_PROCESS_DOWN)
51 ok = 3; 52 ok = 3;
52 else if (ok == 1) 53 else if (ok == 1)
53 ok = 0; 54 ok = 0;
54} 55}
55 56
57
56static void 58static void
57arm_notify_stop (void *cls, int success) 59arm_notify_stop (void *cls, enum GNUNET_ARM_ProcessStatus success)
58{ 60{
59 GNUNET_assert (success == GNUNET_NO); 61 GNUNET_break (success == GNUNET_ARM_PROCESS_DOWN);
60#if START_ARM 62#if START_ARM
61 GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); 63 GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL);
62#endif 64#endif
@@ -67,49 +69,50 @@ static void
67dns_notify (void *cls, const struct sockaddr *addr, socklen_t addrlen) 69dns_notify (void *cls, const struct sockaddr *addr, socklen_t addrlen)
68{ 70{
69 if (addr == NULL) 71 if (addr == NULL)
70 {
71 if (ok != 0)
72 { 72 {
73 GNUNET_break (0); 73 if (ok != 0)
74 ok = 2; 74 {
75 GNUNET_break (0);
76 ok = 2;
77 }
78 GNUNET_ARM_stop_service (arm, "resolver", TIMEOUT, &arm_notify_stop,
79 NULL);
80 return;
75 } 81 }
76 GNUNET_ARM_stop_service (arm, "resolver", TIMEOUT, &arm_notify_stop, NULL); 82 GNUNET_break (addr != NULL);
77 return;
78 }
79 GNUNET_assert (addr != NULL);
80 ok = 0; 83 ok = 0;
81} 84}
82 85
83 86
84static void 87static void
85resolver_notify (void *cls, int success) 88resolver_notify (void *cls, enum GNUNET_ARM_ProcessStatus success)
86{ 89{
87 if (success != GNUNET_YES) 90 if (success != GNUNET_ARM_PROCESS_STARTING)
88 { 91 {
89 GNUNET_break (0); 92 GNUNET_break (0);
90 ok = 2; 93 ok = 2;
91#if START_ARM 94#if START_ARM
92 GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); 95 GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL);
93#endif 96#endif
94 return; 97 return;
95 } 98 }
96 GNUNET_RESOLVER_ip_get ("localhost", AF_INET, TIMEOUT, &dns_notify, NULL); 99 GNUNET_RESOLVER_ip_get ("localhost", AF_INET, TIMEOUT, &dns_notify, NULL);
97} 100}
98 101
99 102
100static void 103static void
101arm_notify (void *cls, int success) 104arm_notify (void *cls, enum GNUNET_ARM_ProcessStatus success)
102{ 105{
103 if (success != GNUNET_YES) 106 if (success != GNUNET_ARM_PROCESS_STARTING)
104 { 107 {
105 GNUNET_break (0); 108 GNUNET_break (0);
106 ok = 2; 109 ok = 2;
107#if START_ARM 110#if START_ARM
108 GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); 111 GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL);
109#endif 112#endif
110 } 113 }
111 GNUNET_ARM_start_service (arm, "resolver", START_TIMEOUT, &resolver_notify, 114 GNUNET_ARM_start_service (arm, "resolver", START_TIMEOUT, &resolver_notify,
112 NULL); 115 NULL);
113} 116}
114 117
115 118
@@ -143,9 +146,9 @@ check ()
143 GNUNET_GETOPT_OPTION_END 146 GNUNET_GETOPT_OPTION_END
144 }; 147 };
145 GNUNET_assert (GNUNET_OK == 148 GNUNET_assert (GNUNET_OK ==
146 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, 149 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
147 argv, "test-arm-api", "nohelp", options, 150 argv, "test-arm-api", "nohelp", options,
148 &task, NULL)); 151 &task, NULL));
149 return ok; 152 return ok;
150} 153}
151 154
@@ -157,11 +160,11 @@ main (int argc, char *argv[])
157 160
158 GNUNET_log_setup ("test-arm-api", 161 GNUNET_log_setup ("test-arm-api",
159#if VERBOSE 162#if VERBOSE
160 "DEBUG", 163 "DEBUG",
161#else 164#else
162 "WARNING", 165 "WARNING",
163#endif 166#endif
164 NULL); 167 NULL);
165 ret = check (); 168 ret = check ();
166 169
167 return ret; 170 return ret;
diff --git a/src/arm/test_exponential_backoff.c b/src/arm/test_exponential_backoff.c
index 3ff4d284f..029ed145a 100644
--- a/src/arm/test_exponential_backoff.c
+++ b/src/arm/test_exponential_backoff.c
@@ -29,22 +29,33 @@
29#include "gnunet_protocols.h" 29#include "gnunet_protocols.h"
30 30
31#define VERBOSE GNUNET_EXTRA_LOGGING 31#define VERBOSE GNUNET_EXTRA_LOGGING
32
32#define START_ARM GNUNET_YES 33#define START_ARM GNUNET_YES
34
33#define LOG_BACKOFF GNUNET_NO 35#define LOG_BACKOFF GNUNET_NO
36
34#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) 37#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
38
35#define SERVICE_TEST_TIMEOUT GNUNET_TIME_UNIT_FOREVER_REL 39#define SERVICE_TEST_TIMEOUT GNUNET_TIME_UNIT_FOREVER_REL
40
36#define FIVE_MILLISECONDS GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 5) 41#define FIVE_MILLISECONDS GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 5)
37 42
43
38static const struct GNUNET_CONFIGURATION_Handle *cfg; 44static const struct GNUNET_CONFIGURATION_Handle *cfg;
45
39static struct GNUNET_ARM_Handle *arm; 46static struct GNUNET_ARM_Handle *arm;
47
40static int ok = 1; 48static int ok = 1;
41 49
42static int trialCount; 50static int trialCount;
51
43static struct GNUNET_TIME_Absolute startedWaitingAt; 52static struct GNUNET_TIME_Absolute startedWaitingAt;
53
44struct GNUNET_TIME_Relative waitedFor; 54struct GNUNET_TIME_Relative waitedFor;
45 55
46#if LOG_BACKOFF 56#if LOG_BACKOFF
47static FILE *killLogFilePtr; 57static FILE *killLogFilePtr;
58
48static char *killLogFileName; 59static char *killLogFileName;
49#endif 60#endif
50 61
@@ -89,7 +100,7 @@ struct ShutdownContext
89/** 100/**
90 * Handler receiving response to service shutdown requests. 101 * Handler receiving response to service shutdown requests.
91 * First call with NULL: service misbehaving, or something. 102 * First call with NULL: service misbehaving, or something.
92 * First call with GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN_ACK: 103 * First call with GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN:
93 * - service will shutdown 104 * - service will shutdown
94 * Second call with NULL: 105 * Second call with NULL:
95 * - service has now really shut down. 106 * - service has now really shut down.
@@ -103,53 +114,56 @@ service_shutdown_handler (void *cls, const struct GNUNET_MessageHeader *msg)
103 struct ShutdownContext *shutdown_ctx = cls; 114 struct ShutdownContext *shutdown_ctx = cls;
104 115
105 if ((msg == NULL) && (shutdown_ctx->confirmed != GNUNET_YES)) 116 if ((msg == NULL) && (shutdown_ctx->confirmed != GNUNET_YES))
106 { 117 {
107 /* Means the other side closed the connection and never confirmed a shutdown */ 118 /* Means the other side closed the connection and never confirmed a shutdown */
108 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 119 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
109 "Service handle shutdown before ACK!\n"); 120 "Service handle shutdown before ACK!\n");
110 if (shutdown_ctx->cont != NULL) 121 if (shutdown_ctx->cont != NULL)
111 shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_SYSERR); 122 shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_SYSERR);
112 GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task); 123 GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task);
113 GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO); 124 GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO);
114 GNUNET_free (shutdown_ctx); 125 GNUNET_free (shutdown_ctx);
115 } 126 }
116 else if ((msg == NULL) && (shutdown_ctx->confirmed == GNUNET_YES)) 127 else if ((msg == NULL) && (shutdown_ctx->confirmed == GNUNET_YES))
117 {
118#if VERBOSE
119 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service shutdown complete.\n");
120#endif
121 if (shutdown_ctx->cont != NULL)
122 shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_NO);
123
124 GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task);
125 GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO);
126 GNUNET_free (shutdown_ctx);
127 }
128 else
129 {
130 GNUNET_assert (ntohs (msg->size) == sizeof (struct GNUNET_MessageHeader));
131 switch (ntohs (msg->type))
132 { 128 {
133 case GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN_ACK:
134#if VERBOSE 129#if VERBOSE
135 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service shutdown complete.\n");
136 "Received confirmation for service shutdown.\n");
137#endif 131#endif
138 shutdown_ctx->confirmed = GNUNET_YES;
139 GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler,
140 shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL);
141 break;
142 default: /* Fall through */
143 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Service shutdown refused!\n");
144 if (shutdown_ctx->cont != NULL) 132 if (shutdown_ctx->cont != NULL)
145 shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_YES); 133 shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_NO);
146 134
147 GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task); 135 GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task);
148 GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO); 136 GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO);
149 GNUNET_free (shutdown_ctx); 137 GNUNET_free (shutdown_ctx);
150 break;
151 } 138 }
152 } 139 else
140 {
141 GNUNET_assert (ntohs (msg->size) ==
142 sizeof (struct GNUNET_MessageHeader));
143 switch (ntohs (msg->type))
144 {
145 case GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN:
146#if VERBOSE
147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
148 "Received confirmation for service shutdown.\n");
149#endif
150 shutdown_ctx->confirmed = GNUNET_YES;
151 GNUNET_CLIENT_receive (shutdown_ctx->sock,
152 &service_shutdown_handler, shutdown_ctx,
153 GNUNET_TIME_UNIT_FOREVER_REL);
154 break;
155 default: /* Fall through */
156 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
157 "Service shutdown refused!\n");
158 if (shutdown_ctx->cont != NULL)
159 shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_YES);
160
161 GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task);
162 GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO);
163 GNUNET_free (shutdown_ctx);
164 break;
165 }
166 }
153} 167}
154 168
155/** 169/**
@@ -160,7 +174,7 @@ service_shutdown_handler (void *cls, const struct GNUNET_MessageHeader *msg)
160 */ 174 */
161void 175void
162service_shutdown_cancel (void *cls, 176service_shutdown_cancel (void *cls,
163 const struct GNUNET_SCHEDULER_TaskContext *tc) 177 const struct GNUNET_SCHEDULER_TaskContext *tc)
164{ 178{
165 struct ShutdownContext *shutdown_ctx = cls; 179 struct ShutdownContext *shutdown_ctx = cls;
166 180
@@ -187,21 +201,21 @@ write_shutdown (void *cls, size_t size, void *buf)
187 struct ShutdownContext *shutdown_ctx = cls; 201 struct ShutdownContext *shutdown_ctx = cls;
188 202
189 if (size < sizeof (struct GNUNET_MessageHeader)) 203 if (size < sizeof (struct GNUNET_MessageHeader))
190 { 204 {
191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
192 _("Failed to transmit shutdown request to client.\n")); 206 _("Failed to transmit shutdown request to client.\n"));
193 shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_SYSERR); 207 shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_SYSERR);
194 GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO); 208 GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO);
195 GNUNET_free (shutdown_ctx); 209 GNUNET_free (shutdown_ctx);
196 return 0; /* client disconnected */ 210 return 0; /* client disconnected */
197 } 211 }
198 212
199 GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler, 213 GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler,
200 shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL); 214 shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL);
201 shutdown_ctx->cancel_task = 215 shutdown_ctx->cancel_task =
202 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining 216 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
203 (shutdown_ctx->timeout), 217 (shutdown_ctx->timeout),
204 &service_shutdown_cancel, shutdown_ctx); 218 &service_shutdown_cancel, shutdown_ctx);
205 msg = (struct GNUNET_MessageHeader *) buf; 219 msg = (struct GNUNET_MessageHeader *) buf;
206 msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN); 220 msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN);
207 msg->size = htons (sizeof (struct GNUNET_MessageHeader)); 221 msg->size = htons (sizeof (struct GNUNET_MessageHeader));
@@ -224,8 +238,8 @@ write_shutdown (void *cls, size_t size, void *buf)
224 */ 238 */
225static void 239static void
226arm_service_shutdown (struct GNUNET_CLIENT_Connection *sock, 240arm_service_shutdown (struct GNUNET_CLIENT_Connection *sock,
227 struct GNUNET_TIME_Relative timeout, 241 struct GNUNET_TIME_Relative timeout,
228 GNUNET_CLIENT_ShutdownTask cont, void *cont_cls) 242 GNUNET_CLIENT_ShutdownTask cont, void *cont_cls)
229{ 243{
230 struct ShutdownContext *shutdown_ctx; 244 struct ShutdownContext *shutdown_ctx;
231 245
@@ -235,16 +249,17 @@ arm_service_shutdown (struct GNUNET_CLIENT_Connection *sock,
235 shutdown_ctx->sock = sock; 249 shutdown_ctx->sock = sock;
236 shutdown_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); 250 shutdown_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
237 GNUNET_CLIENT_notify_transmit_ready (sock, 251 GNUNET_CLIENT_notify_transmit_ready (sock,
238 sizeof (struct GNUNET_MessageHeader), 252 sizeof (struct GNUNET_MessageHeader),
239 timeout, GNUNET_NO, &write_shutdown, 253 timeout, GNUNET_NO, &write_shutdown,
240 shutdown_ctx); 254 shutdown_ctx);
241} 255}
242 256
243 257
244static void 258static void
245arm_notify_stop (void *cls, int success) 259arm_notify_stop (void *cls, enum GNUNET_ARM_ProcessStatus status)
246{ 260{
247 GNUNET_assert (success == GNUNET_NO); 261 GNUNET_assert ( (status == GNUNET_ARM_PROCESS_DOWN) ||
262 (status == GNUNET_ARM_PROCESS_ALREADY_DOWN) );
248#if START_ARM 263#if START_ARM
249 GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, NULL, NULL); 264 GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, NULL, NULL);
250#endif 265#endif
@@ -256,20 +271,19 @@ kill_task (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc);
256 271
257 272
258static void 273static void
259do_nothing_notify (void *cls, int success) 274do_nothing_notify (void *cls, enum GNUNET_ARM_ProcessStatus status)
260{ 275{
261 GNUNET_assert (success == GNUNET_YES); 276 GNUNET_assert (status == GNUNET_ARM_PROCESS_STARTING);
262 ok = 1; 277 ok = 1;
263 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &kill_task, NULL); 278 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &kill_task, NULL);
264} 279}
265 280
266
267static void 281static void
268arm_notify (void *cls, int success) 282arm_notify (void *cls, enum GNUNET_ARM_ProcessStatus status)
269{ 283{
270 GNUNET_assert (success == GNUNET_YES); 284 GNUNET_assert (status == GNUNET_ARM_PROCESS_STARTING);
271 GNUNET_ARM_start_service (arm, "do-nothing", TIMEOUT, &do_nothing_notify, 285 GNUNET_ARM_start_service (arm, "do-nothing", TIMEOUT, &do_nothing_notify,
272 NULL); 286 NULL);
273} 287}
274 288
275 289
@@ -279,7 +293,8 @@ kill_task (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc);
279 293
280static void 294static void
281do_nothing_restarted_notify_task (void *cls, 295do_nothing_restarted_notify_task (void *cls,
282 const struct GNUNET_SCHEDULER_TaskContext *tc) 296 const struct GNUNET_SCHEDULER_TaskContext
297 *tc)
283{ 298{
284 static char a; 299 static char a;
285 300
@@ -287,17 +302,17 @@ do_nothing_restarted_notify_task (void *cls,
287 302
288#if LOG_BACKOFF 303#if LOG_BACKOFF
289 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) 304 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
290 { 305 {
291 fprintf (killLogFilePtr, "%d.Reason is shutdown!\n", trialCount); 306 fprintf (killLogFilePtr, "%d.Reason is shutdown!\n", trialCount);
292 } 307 }
293 else if ((tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT) != 0) 308 else if ((tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT) != 0)
294 { 309 {
295 fprintf (killLogFilePtr, "%d.Reason is timeout!\n", trialCount); 310 fprintf (killLogFilePtr, "%d.Reason is timeout!\n", trialCount);
296 } 311 }
297 else if ((tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE) != 0) 312 else if ((tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE) != 0)
298 { 313 {
299 fprintf (killLogFilePtr, "%d.Service is running!\n", trialCount); 314 fprintf (killLogFilePtr, "%d.Service is running!\n", trialCount);
300 } 315 }
301#endif 316#endif
302 GNUNET_SCHEDULER_add_now (&kill_task, &a); 317 GNUNET_SCHEDULER_add_now (&kill_task, &a);
303} 318}
@@ -307,7 +322,7 @@ static void
307do_test (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc) 322do_test (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc)
308{ 323{
309 GNUNET_CLIENT_service_test ("do-nothing", cfg, TIMEOUT, 324 GNUNET_CLIENT_service_test ("do-nothing", cfg, TIMEOUT,
310 &do_nothing_restarted_notify_task, NULL); 325 &do_nothing_restarted_notify_task, NULL);
311} 326}
312 327
313 328
@@ -326,29 +341,29 @@ kill_task (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc)
326 static struct GNUNET_CLIENT_Connection *doNothingConnection = NULL; 341 static struct GNUNET_CLIENT_Connection *doNothingConnection = NULL;
327 342
328 if (NULL != cbData) 343 if (NULL != cbData)
329 { 344 {
330 waitedFor = GNUNET_TIME_absolute_get_duration (startedWaitingAt); 345 waitedFor = GNUNET_TIME_absolute_get_duration (startedWaitingAt);
331 346
332#if LOG_BACKOFF 347#if LOG_BACKOFF
333 fprintf (killLogFilePtr, "Waited for: %llu ms\n", 348 fprintf (killLogFilePtr, "Waited for: %llu ms\n",
334 (unsigned long long) waitedFor.rel_value); 349 (unsigned long long) waitedFor.rel_value);
335#endif 350#endif
336 } 351 }
337 else 352 else
338 { 353 {
339 waitedFor.rel_value = 0; 354 waitedFor.rel_value = 0;
340 } 355 }
341 /* Connect to the doNothing task */ 356 /* Connect to the doNothing task */
342 doNothingConnection = GNUNET_CLIENT_connect ("do-nothing", cfg); 357 doNothingConnection = GNUNET_CLIENT_connect ("do-nothing", cfg);
343 GNUNET_assert (doNothingConnection != NULL); 358 GNUNET_assert (doNothingConnection != NULL);
344 if (trialCount == 12) 359 if (trialCount == 12)
345 { 360 {
346 GNUNET_CLIENT_disconnect (doNothingConnection, GNUNET_NO); 361 GNUNET_CLIENT_disconnect (doNothingConnection, GNUNET_NO);
347 GNUNET_ARM_stop_service (arm, "do-nothing", TIMEOUT, &arm_notify_stop, 362 GNUNET_ARM_stop_service (arm, "do-nothing", TIMEOUT, &arm_notify_stop,
348 NULL); 363 NULL);
349 ok = 0; 364 ok = 0;
350 return; 365 return;
351 } 366 }
352 /* Use the created connection to kill the doNothingTask */ 367 /* Use the created connection to kill the doNothingTask */
353 arm_service_shutdown (doNothingConnection, TIMEOUT, &shutdown_cont, NULL); 368 arm_service_shutdown (doNothingConnection, TIMEOUT, &shutdown_cont, NULL);
354} 369}
@@ -363,7 +378,7 @@ task (void *cls, char *const *args, const char *cfgfile,
363 arm = GNUNET_ARM_connect (cfg, NULL); 378 arm = GNUNET_ARM_connect (cfg, NULL);
364#if START_ARM 379#if START_ARM
365 GNUNET_ARM_start_service (arm, "arm", GNUNET_TIME_UNIT_ZERO, &arm_notify, 380 GNUNET_ARM_start_service (arm, "arm", GNUNET_TIME_UNIT_ZERO, &arm_notify,
366 NULL); 381 NULL);
367#else 382#else
368 arm_do_nothing (NULL, GNUNET_YES); 383 arm_do_nothing (NULL, GNUNET_YES);
369#endif 384#endif
@@ -387,9 +402,9 @@ check ()
387 402
388 /* Running ARM and running the do_nothing task */ 403 /* Running ARM and running the do_nothing task */
389 GNUNET_assert (GNUNET_OK == 404 GNUNET_assert (GNUNET_OK ==
390 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, 405 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
391 argv, "test-exponential-backoff", "nohelp", 406 argv, "test-exponential-backoff",
392 options, &task, NULL)); 407 "nohelp", options, &task, NULL));
393 408
394 409
395 return ok; 410 return ok;
@@ -401,12 +416,12 @@ init ()
401#if LOG_BACKOFF 416#if LOG_BACKOFF
402 killLogFileName = GNUNET_DISK_mktemp ("exponential-backoff-waiting.log"); 417 killLogFileName = GNUNET_DISK_mktemp ("exponential-backoff-waiting.log");
403 if (NULL == (killLogFilePtr = FOPEN (killLogFileName, "w"))) 418 if (NULL == (killLogFilePtr = FOPEN (killLogFileName, "w")))
404 { 419 {
405 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "fopen", 420 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "fopen",
406 killLogFileName); 421 killLogFileName);
407 GNUNET_free (killLogFileName); 422 GNUNET_free (killLogFileName);
408 return GNUNET_SYSERR; 423 return GNUNET_SYSERR;
409 } 424 }
410#endif 425#endif
411 return GNUNET_OK; 426 return GNUNET_OK;
412} 427}
@@ -429,11 +444,11 @@ main (int argc, char *argv[])
429 444
430 GNUNET_log_setup ("test-exponential-backoff", 445 GNUNET_log_setup ("test-exponential-backoff",
431#if VERBOSE 446#if VERBOSE
432 "DEBUG", 447 "DEBUG",
433#else 448#else
434 "WARNING", 449 "WARNING",
435#endif 450#endif
436 NULL); 451 NULL);
437 452
438 init (); 453 init ();
439 ret = check (); 454 ret = check ();
diff --git a/src/arm/test_gnunet_arm.sh b/src/arm/test_gnunet_arm.sh
index d36c2ca38..4a5b7266d 100755
--- a/src/arm/test_gnunet_arm.sh
+++ b/src/arm/test_gnunet_arm.sh
@@ -40,28 +40,6 @@ sleep 1
40echo "PASS" 40echo "PASS"
41 41
42# ---------------------------------------------------------------------------------- 42# ----------------------------------------------------------------------------------
43echo -n "TEST: Test -t on running service... "
44if ! $exe $DEBUG -t resolver > $out; then
45 echo "FAIL: error running $exe"
46 exit 1
47fi
48LINES=`cat $out | grep resolver | grep not | wc -l`
49if test $LINES -ne 0; then
50 echo "FAIL: unexpected output:"
51 cat $out
52 $exe -e
53 exit 1
54fi
55LINES=`cat $out | grep resolver | grep -v not | wc -l`
56if test $LINES -ne 1; then
57 echo "FAIL: unexpected output"
58 cat $out
59 $exe -e
60 exit 1
61fi
62echo "PASS"
63
64# ----------------------------------------------------------------------------------
65echo -n "TEST: Stop a service... " 43echo -n "TEST: Stop a service... "
66 44
67if ! $exe $DEBUG -k resolver > $out; then 45if ! $exe $DEBUG -k resolver > $out; then
@@ -73,23 +51,6 @@ sleep 1
73echo "PASS" 51echo "PASS"
74 52
75# ---------------------------------------------------------------------------------- 53# ----------------------------------------------------------------------------------
76echo -n "TEST: Test -t on stopped service... "
77if ! $exe $DEBUG -t resolver > $out; then
78 echo "FAIL: error running $exe"
79 cat $out
80 $exe -e > /dev/null
81 exit 1
82fi
83LINES=`cat $out | grep resolver | grep not | wc -l`
84if test $LINES -ne 1; then
85 echo "FAIL: unexpected output"
86 cat $out
87 $exe -e > /dev/null
88 exit 1
89fi
90echo "PASS"
91
92# ----------------------------------------------------------------------------------
93echo -n "TEST: Stop ARM... " 54echo -n "TEST: Stop ARM... "
94 55
95if ! $exe $DEBUG -e > $out; then 56if ! $exe $DEBUG -e > $out; then
diff --git a/src/arm/test_gnunet_service_manager.c b/src/arm/test_gnunet_service_manager.c
index 100e1569c..2be86e79f 100644
--- a/src/arm/test_gnunet_service_manager.c
+++ b/src/arm/test_gnunet_service_manager.c
@@ -51,17 +51,17 @@ static struct GNUNET_ARM_Handle *arm;
51#endif 51#endif
52 52
53static void 53static void
54arm_stopped (void *cls, int success) 54arm_stopped (void *cls, enum GNUNET_ARM_ProcessStatus success)
55{ 55{
56 if (success != GNUNET_NO) 56 if (success != GNUNET_ARM_PROCESS_DOWN)
57 { 57 {
58 GNUNET_break (0); 58 GNUNET_break (0);
59 ret = 4; 59 ret = 4;
60 } 60 }
61 else 61 else
62 { 62 {
63 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM stopped\n"); 63 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM stopped\n");
64 } 64 }
65#if START_ARM 65#if START_ARM
66 GNUNET_ARM_disconnect (arm); 66 GNUNET_ARM_disconnect (arm);
67 arm = NULL; 67 arm = NULL;
@@ -74,15 +74,16 @@ hostNameResolveCB (void *cls, const struct sockaddr *addr, socklen_t addrlen)
74 if ((ret == 0) || (ret == 4)) 74 if ((ret == 0) || (ret == 4))
75 return; 75 return;
76 if (NULL == addr) 76 if (NULL == addr)
77 { 77 {
78 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Name not resolved!\n"); 78 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Name not resolved!\n");
79#if START_ARM 79#if START_ARM
80 GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); 80 GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL);
81#endif 81#endif
82 ret = 3; 82 ret = 3;
83 return; 83 return;
84 } 84 }
85 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Resolved hostname, now stopping ARM\n"); 85 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
86 "Resolved hostname, now stopping ARM\n");
86 ret = 0; 87 ret = 0;
87#if START_ARM 88#if START_ARM
88 GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); 89 GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL);
@@ -91,27 +92,28 @@ hostNameResolveCB (void *cls, const struct sockaddr *addr, socklen_t addrlen)
91 92
92 93
93static void 94static void
94arm_notify (void *cls, int success) 95arm_notify (void *cls, enum GNUNET_ARM_ProcessStatus success)
95{ 96{
96 if (success != GNUNET_YES) 97 if (success != GNUNET_ARM_PROCESS_STARTING)
97 { 98 {
98 GNUNET_break (0); 99 GNUNET_break (0);
99 ret = 1; 100 ret = 1;
100 return; 101 return;
101 } 102 }
102 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to resolve our own hostname!\n"); 103 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
104 "Trying to resolve our own hostname!\n");
103 /* connect to the resolver service */ 105 /* connect to the resolver service */
104 if (NULL == 106 if (NULL ==
105 GNUNET_RESOLVER_hostname_resolve (AF_UNSPEC, TIMEOUT, &hostNameResolveCB, 107 GNUNET_RESOLVER_hostname_resolve (AF_UNSPEC, TIMEOUT,
106 NULL)) 108 &hostNameResolveCB, NULL))
107 { 109 {
108 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 110 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
109 "Unable initiate connection to resolver service\n"); 111 "Unable initiate connection to resolver service\n");
110 ret = 2; 112 ret = 2;
111#if START_ARM 113#if START_ARM
112 GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); 114 GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL);
113#endif 115#endif
114 } 116 }
115} 117}
116 118
117 119
@@ -144,9 +146,9 @@ check ()
144 GNUNET_GETOPT_OPTION_END 146 GNUNET_GETOPT_OPTION_END
145 }; 147 };
146 GNUNET_assert (GNUNET_OK == 148 GNUNET_assert (GNUNET_OK ==
147 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, 149 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
148 argv, "test-gnunet-service-manager", 150 argv, "test-gnunet-service-manager",
149 "nohelp", options, &run, NULL)); 151 "nohelp", options, &run, NULL));
150} 152}
151 153
152 154
@@ -156,27 +158,28 @@ main (int argc, char *argv[])
156 char hostname[GNUNET_OS_get_hostname_max_length () + 1]; 158 char hostname[GNUNET_OS_get_hostname_max_length () + 1];
157 159
158 if (0 != gethostname (hostname, sizeof (hostname) - 1)) 160 if (0 != gethostname (hostname, sizeof (hostname) - 1))
159 { 161 {
160 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 162 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
161 "gethostname"); 163 "gethostname");
162 fprintf (stderr, 164 fprintf (stderr,
163 "Failed to determine my own hostname, testcase not run.\n"); 165 "Failed to determine my own hostname, testcase not run.\n");
164 return 0; 166 return 0;
165 } 167 }
166 if (NULL == gethostbyname (hostname)) 168 if (NULL == gethostbyname (hostname))
167 { 169 {
168 fprintf (stderr, "Failed to resolve my hostname `%s', testcase not run.\n", 170 fprintf (stderr,
169 hostname); 171 "Failed to resolve my hostname `%s', testcase not run.\n",
170 return 0; 172 hostname);
171 } 173 return 0;
174 }
172 175
173 GNUNET_log_setup ("test-gnunet-service-manager", 176 GNUNET_log_setup ("test-gnunet-service-manager",
174#if VERBOSE 177#if VERBOSE
175 "DEBUG", 178 "DEBUG",
176#else 179#else
177 "WARNING", 180 "WARNING",
178#endif 181#endif
179 NULL); 182 NULL);
180 check (); 183 check ();
181 return ret; 184 return ret;
182} 185}