aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/man/gnunet-arm.116
-rw-r--r--po/POTFILES.in2
-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
-rw-r--r--src/include/gnunet_arm_service.h67
-rw-r--r--src/include/gnunet_protocols.h24
15 files changed, 1318 insertions, 1537 deletions
diff --git a/doc/man/gnunet-arm.1 b/doc/man/gnunet-arm.1
index 30e0082ef..e8b7c7a61 100644
--- a/doc/man/gnunet-arm.1
+++ b/doc/man/gnunet-arm.1
@@ -9,7 +9,7 @@ gnunet\-arm \- control GNUnet services
9.br 9.br
10 10
11.SH DESCRIPTION 11.SH DESCRIPTION
12\fBgnunet\-arm\fP can be used to start or stop GNUnet services, including the ARM service itself. 12\fBgnunet\-arm\fP can be used to start or stop GNUnet services, including the ARM service itself. The ARM service is a supervisor for GNUnet's service processes. ARM starts services on-demand or as configured and re-starts them if they crash.
13 13
14.SH OPTIONS 14.SH OPTIONS
15 15
@@ -19,7 +19,7 @@ Use the configuration file FILENAME.
19 19
20.TP 20.TP
21.IP "\-e, \-\-end" 21.IP "\-e, \-\-end"
22Shutdown all GNUnet services (including ARM). 22Shutdown all GNUnet services (including ARM itself). Running "gnunet-arm -e" is the usual way to shutdown a GNUnet peer.
23 23
24.TP 24.TP
25.IP "\-h, \-\-help" 25.IP "\-h, \-\-help"
@@ -31,19 +31,15 @@ Use LOGLEVEL for logging. Valid values are DEBUG, INFO, WARNING and ERROR.
31 31
32.TP 32.TP
33.IP "\-i SERVICE, \-\-init=SERVICE" 33.IP "\-i SERVICE, \-\-init=SERVICE"
34Starts the specified SERVICE if it is not already running. 34Starts the specified SERVICE if it is not already running. More specifically, this makes the service behave as if it were in the default services list.
35 35
36.TP 36.TP
37.IP "\-k SERVICE, \-\-kill=SERVICE" 37.IP "\-k SERVICE, \-\-kill=SERVICE"
38Stop the specified SERVICE if it is running. 38Stop the specified SERVICE if it is running. While this will kill the service right now, the service may be restarted immediately if other services depend on it (service is then started 'on-demand'). If the service used to be a 'default' service, its default-service status will be revoked. If the service was not a default service, it will just be (temporarily) stopped, but could be re-started on-demand at any time.
39 39
40.TP 40.TP
41.IP "\-s, \-\-start" 41.IP "\-s, \-\-start"
42Start all GNUnet default services on this system (including ARM). 42Start all GNUnet default services on this system (and also ARM). Naturally, if a service is demanded by a default service, it will then also be started. Running "gnunet-arm -s" is the usual way to start a GNUnet peer.
43
44.TP
45.IP "\-t SERVICE, \-\-test=SERVICE"
46Report if the specified SERVICE is running.
47 43
48.TP 44.TP
49.IP "\-v, \-\-version" 45.IP "\-v, \-\-version"
@@ -51,7 +47,7 @@ Print GNUnet version number.
51 47
52 48
53.SH BUGS 49.SH BUGS
54Report bugs by using Mantis <https://gnunet.org/mantis/> or by sending electronic mail to <gnunet\-developers@gnu.org> 50Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <gnunet\-developers@gnu.org>
55 51
56.SH SEE ALSO 52.SH SEE ALSO
57gnunet\-service\-arm(1) 53gnunet\-service\-arm(1)
diff --git a/po/POTFILES.in b/po/POTFILES.in
index dc8e00a3f..c008d61dd 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -95,7 +95,6 @@ src/arm/gnunet-arm.c
95src/arm/mockup-service.c 95src/arm/mockup-service.c
96src/arm/gnunet-service-arm.c 96src/arm/gnunet-service-arm.c
97src/arm/arm_api.c 97src/arm/arm_api.c
98src/arm/gnunet-service-arm_interceptor.c
99src/arm/do_start_process.c 98src/arm/do_start_process.c
100src/ats/gnunet-service-ats_reservations.c 99src/ats/gnunet-service-ats_reservations.c
101src/ats/ats_api.c 100src/ats/ats_api.c
@@ -219,7 +218,6 @@ src/dht/gnunet-service-dht.h
219src/dht/gnunet-service-dht_hello.h 218src/dht/gnunet-service-dht_hello.h
220src/dht/gnunet-service-dht_nse.h 219src/dht/gnunet-service-dht_nse.h
221src/arm/arm.h 220src/arm/arm.h
222src/arm/gnunet-service-arm.h
223src/ats/gnunet-service-ats_performance.h 221src/ats/gnunet-service-ats_performance.h
224src/ats/gnunet-service-ats_math.h 222src/ats/gnunet-service-ats_math.h
225src/ats/gnunet-service-ats.h 223src/ats/gnunet-service-ats.h
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}
diff --git a/src/include/gnunet_arm_service.h b/src/include/gnunet_arm_service.h
index 6d52773de..af1c8cd94 100644
--- a/src/include/gnunet_arm_service.h
+++ b/src/include/gnunet_arm_service.h
@@ -42,19 +42,74 @@ extern "C"
42/** 42/**
43 * Version of the arm API. 43 * Version of the arm API.
44 */ 44 */
45#define GNUNET_ARM_VERSION 0x00000000 45#define GNUNET_ARM_VERSION 0x00000001
46
47
48/**
49 * Values characterizing GNUnet process states.
50 */
51enum GNUNET_ARM_ProcessStatus
52{
53 /**
54 * Service name is unknown to ARM.
55 */
56 GNUNET_ARM_PROCESS_UNKNOWN = -1,
57
58 /**
59 * Service is now down (due to client request).
60 */
61 GNUNET_ARM_PROCESS_DOWN = 0,
62
63 /**
64 * Service is already running.
65 */
66 GNUNET_ARM_PROCESS_ALREADY_RUNNING = 1,
67
68 /**
69 * Service is currently being started (due to client request).
70 */
71 GNUNET_ARM_PROCESS_STARTING = 2,
72
73 /**
74 * Service is already being stopped by some other client.
75 */
76 GNUNET_ARM_PROCESS_ALREADY_STOPPING = 3,
77
78 /**
79 * Service is already down (no action taken)
80 */
81 GNUNET_ARM_PROCESS_ALREADY_DOWN = 4,
82
83 /**
84 * ARM is currently being shut down (no more process starts)
85 */
86 GNUNET_ARM_PROCESS_SHUTDOWN = 5,
87
88 /**
89 * Error in communication with ARM
90 */
91 GNUNET_ARM_PROCESS_COMMUNICATION_ERROR = 6,
92
93 /**
94 * Timeout in communication with ARM
95 */
96 GNUNET_ARM_PROCESS_COMMUNICATION_TIMEOUT = 7,
97
98 /**
99 * Failure to perform operation
100 */
101 GNUNET_ARM_PROCESS_FAILURE = 8
102};
46 103
47 104
48/** 105/**
49 * Callback function invoked when operation is complete. 106 * Callback function invoked when operation is complete.
50 * 107 *
51 * @param cls closure 108 * @param cls closure
52 * @param success GNUNET_YES if we think the service is running 109 * @param result outcome of the operation
53 * GNUNET_NO if we think the service is stopped
54 * GNUNET_SYSERR if we think ARM was not running or
55 * if the service status is unknown
56 */ 110 */
57typedef void (*GNUNET_ARM_Callback) (void *cls, int success); 111typedef void (*GNUNET_ARM_Callback) (void *cls,
112 enum GNUNET_ARM_ProcessStatus result);
58 113
59 114
60/** 115/**
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h
index e959a5cf9..5b9f0612a 100644
--- a/src/include/gnunet_protocols.h
+++ b/src/include/gnunet_protocols.h
@@ -78,31 +78,15 @@ extern "C"
78#define GNUNET_MESSAGE_TYPE_ARM_STOP 9 78#define GNUNET_MESSAGE_TYPE_ARM_STOP 9
79 79
80/** 80/**
81 * Response from ARM: service is now up. 81 * Request ARM service itself to shutdown.
82 */ 82 */
83#define GNUNET_MESSAGE_TYPE_ARM_IS_UP 10 83#define GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN 10
84 84
85/** 85/**
86 * Response from ARM: service is now down. 86 * Response from ARM.
87 * (failed to start it or shut it down).
88 */ 87 */
89#define GNUNET_MESSAGE_TYPE_ARM_IS_DOWN 11 88#define GNUNET_MESSAGE_TYPE_ARM_RESULT 11
90 89
91/**
92 * Response from ARM: service status is unknown.
93 */
94#define GNUNET_MESSAGE_TYPE_ARM_IS_UNKNOWN 12
95
96/**
97 * Request ARM service shutdown.
98 */
99#define GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN 13
100
101/**
102 * Acknowledge service shutting down, disconnect
103 * indicates service stopped.
104 */
105#define GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN_ACK 14
106 90
107/******************************************************************************* 91/*******************************************************************************
108 * HELLO message types 92 * HELLO message types