aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2009-10-05 09:56:25 +0000
committerChristian Grothoff <christian@grothoff.org>2009-10-05 09:56:25 +0000
commitd75fb1880a887a8f5339c5e8cf5e9d2b8755fdad (patch)
treef8dff53b4b88b0d87ca31a772607ee51fb0653ec
parentb9b0940e261a4b1713d909f0a2fd54134ed5b148 (diff)
downloadgnunet-d75fb1880a887a8f5339c5e8cf5e9d2b8755fdad.tar.gz
gnunet-d75fb1880a887a8f5339c5e8cf5e9d2b8755fdad.zip
improving ARM API
-rw-r--r--BUGS2
-rw-r--r--src/arm/arm_api.c564
-rw-r--r--src/arm/gnunet-arm.c152
-rw-r--r--src/arm/gnunet-service-arm.c87
-rw-r--r--src/arm/test_arm_api.c28
-rw-r--r--src/core/test_core_api.c10
-rw-r--r--src/core/test_core_api_start_only.c6
-rw-r--r--src/include/gnunet_arm_service.h92
-rw-r--r--src/testing/testing.c69
-rw-r--r--src/transport/transport_api.c13
10 files changed, 815 insertions, 208 deletions
diff --git a/BUGS b/BUGS
index 31f791f72..affae73e8 100644
--- a/BUGS
+++ b/BUGS
@@ -92,8 +92,6 @@ sane end-user should care about this codebase yet anyway.
92 - implement exponential back-off for service restarts 92 - implement exponential back-off for service restarts
93 - better tracking of which config changes actually need to cause process restarts by ARM. 93 - better tracking of which config changes actually need to cause process restarts by ARM.
94 - have way to specify dependencies between services (to manage ARM restarts better) 94 - have way to specify dependencies between services (to manage ARM restarts better)
95 - client-API is inefficient since it opens a TCP connection per service that is started
96 (instead of re-using connections).
97* CORE: 95* CORE:
98 - code currently notifies clients about "encrypted" connections being up well before 96 - code currently notifies clients about "encrypted" connections being up well before
99 we get the encrypted PONG; sometimes this may be OK (for topology killing 97 we get the encrypted PONG; sometimes this may be OK (for topology killing
diff --git a/src/arm/arm_api.c b/src/arm/arm_api.c
index f0ab8d189..7f2274958 100644
--- a/src/arm/arm_api.c
+++ b/src/arm/arm_api.c
@@ -32,85 +32,200 @@
32#include "gnunet_server_lib.h" 32#include "gnunet_server_lib.h"
33#include "arm.h" 33#include "arm.h"
34 34
35/**
36 * How often do we re-try tranmsitting requests to ARM before
37 * giving up? Note that if we succeeded transmitting a request
38 * but failed to read a response, we do NOT re-try (since that
39 * might result in ARM getting a request twice).
40 */
41#define MAX_ATTEMPTS 4
35 42
36/** 43/**
37 * FIXME: document. 44 * Minimum delay between attempts to talk to ARM.
38 */ 45 */
39struct ArmContext 46#define MIN_RETRY_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100)
47
48
49/**
50 * How long are we willing to wait for a service operation during the multi-operation
51 * request processing?
52 */
53#define MULTI_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
54
55
56/**
57 * Handle for interacting with ARM.
58 */
59struct GNUNET_ARM_Handle
40{ 60{
41 61
42 /** 62 /**
43 * FIXME: document. 63 * Our connection to the ARM service.
64 */
65 struct GNUNET_CLIENT_Connection *client;
66
67 /**
68 * The configuration that we are using.
69 */
70 const struct GNUNET_CONFIGURATION_Handle *cfg;
71
72 /**
73 * Scheduler to use.
74 */
75 struct GNUNET_SCHEDULER_Handle *sched;
76
77};
78
79
80/**
81 * Setup a context for communicating with ARM. Note that this
82 * can be done even if the ARM service is not yet running.
83 *
84 * @param cfg configuration to use (needed to contact ARM;
85 * the ARM service may internally use a different
86 * configuration to determine how to start the service).
87 * @param sched scheduler to use
88 * @param service service that *this* process is implementing/providing, can be NULL
89 * @return context to use for further ARM operations, NULL on error
90 */
91struct GNUNET_ARM_Handle *
92GNUNET_ARM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
93 struct GNUNET_SCHEDULER_Handle *sched,
94 const char *service)
95{
96 struct GNUNET_ARM_Handle *ret;
97 struct GNUNET_CLIENT_Connection *client;
98
99 client = GNUNET_CLIENT_connect (sched, "arm", cfg);
100 if (client == NULL)
101 return NULL;
102 ret = GNUNET_malloc (sizeof (struct GNUNET_ARM_Handle));
103 ret->cfg = cfg;
104 ret->sched = sched;
105 ret->client = client;
106 return ret;
107}
108
109
110/**
111 * Disconnect from the ARM service.
112 *
113 * @param h the handle that was being used
114 */
115void
116GNUNET_ARM_disconnect (struct GNUNET_ARM_Handle *h)
117{
118 if (h->client != NULL)
119 GNUNET_CLIENT_disconnect (h->client);
120 GNUNET_free (h);
121}
122
123
124/**
125 * Internal state for a request with ARM.
126 */
127struct RequestContext
128{
129
130 /**
131 * Pointer to our handle with ARM.
132 */
133 struct GNUNET_ARM_Handle *h;
134
135 /**
136 * Function to call with a status code for the requested operation.
44 */ 137 */
45 GNUNET_ARM_Callback callback; 138 GNUNET_ARM_Callback callback;
46 139
47 /** 140 /**
48 * FIXME: document. 141 * Closure for "callback".
49 */ 142 */
50 void *cls; 143 void *cls;
51 144
52 /** 145 /**
53 * FIXME: document. 146 * The service that is being manipulated. Do not free.
54 */ 147 */
55 char *service_name; 148 const char *service_name;
56 149
57 /** 150 /**
58 * FIXME: document. 151 * Timeout for the operation.
59 */ 152 */
60 struct GNUNET_CLIENT_Connection *client; 153 struct GNUNET_TIME_Absolute timeout;
61 154
62 /** 155 /**
63 * FIXME: document. 156 * Length of service_name plus one.
64 */ 157 */
65 const struct GNUNET_CONFIGURATION_Handle *cfg; 158 size_t slen;
66 159
67 /** 160 /**
68 * FIXME: document. 161 * Number of attempts left for transmitting the request to ARM.
162 * We may fail the first time (say because ARM is not yet up),
163 * in which case we wait a bit and re-try (timeout permitting).
69 */ 164 */
70 struct GNUNET_TIME_Absolute timeout; 165 unsigned int attempts_left;
71 166
72 /** 167 /**
73 * FIXME: document. 168 * Type of the request expressed as a message type (start or stop).
74 */ 169 */
75 uint16_t type; 170 uint16_t type;
171
76}; 172};
77 173
78 174
79/** 175/**
80 * FIXME: document. 176 * A client specifically requested starting of ARM itself.
177 * This function is called with information about whether
178 * or not ARM is running; if it is, report success. If
179 * it is not, start the ARM process.
180 *
181 * @param cls the context for the request that we will report on (struct RequestContext*)
182 * @param tc why were we called (reason says if ARM is running)
81 */ 183 */
82static void 184static void
83arm_service_report (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 185arm_service_report (void *cls,
186 const struct GNUNET_SCHEDULER_TaskContext *tc)
84{ 187{
85 struct ArmContext *pos = cls; 188 struct RequestContext *pos = cls;
86 pid_t pid; 189 pid_t pid;
87 char *binary; 190 char *binary;
88 char *config; 191 char *config;
89 192
90 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) 193 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE))
91 { 194 {
195 /* arm is running! */
92 if (pos->callback != NULL) 196 if (pos->callback != NULL)
93 pos->callback (pos->cls, GNUNET_YES); 197 pos->callback (pos->cls, GNUNET_YES);
94 GNUNET_free (pos); 198 GNUNET_free (pos);
95 return; 199 return;
96 } 200 }
97 binary = NULL; 201 /* FIXME: should we check that HOSTNAME for 'arm' is localhost? */
98 config = NULL;
99 /* start service */ 202 /* start service */
100 if ((GNUNET_OK != 203 if (GNUNET_OK !=
101 GNUNET_CONFIGURATION_get_value_string (pos->cfg, 204 GNUNET_CONFIGURATION_get_value_string (pos->h->cfg,
102 "arm", 205 "arm",
103 "BINARY", 206 "BINARY",
104 &binary)) || 207 &binary))
105 (GNUNET_OK != 208 {
106 GNUNET_CONFIGURATION_get_value_filename (pos->cfg, 209 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
107 "arm", "CONFIG", &config))) 210 _("Configuration failes to specify option `%s' in section `%s'!\n"),
211 "BINARY",
212 "arm");
213 if (pos->callback != NULL)
214 pos->callback (pos->cls, GNUNET_SYSERR);
215 GNUNET_free (pos);
216 return;
217 }
218 if (GNUNET_OK !=
219 GNUNET_CONFIGURATION_get_value_filename (pos->h->cfg,
220 "arm", "CONFIG", &config))
108 { 221 {
109 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 222 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
110 _("Configuration file or binary for ARM not known!\n")); 223 _("Configuration fails to specify option `%s' in section `%s'!\n"),
224 "CONFIG",
225 "arm");
111 if (pos->callback != NULL) 226 if (pos->callback != NULL)
112 pos->callback (pos->cls, GNUNET_SYSERR); 227 pos->callback (pos->cls, GNUNET_SYSERR);
113 GNUNET_free_non_null (binary); 228 GNUNET_free (binary);
114 GNUNET_free (pos); 229 GNUNET_free (pos);
115 return; 230 return;
116 } 231 }
@@ -128,24 +243,34 @@ arm_service_report (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
128 GNUNET_free (pos); 243 GNUNET_free (pos);
129 return; 244 return;
130 } 245 }
131 /* FIXME: consider checking again to see if it worked!? */
132 if (pos->callback != NULL) 246 if (pos->callback != NULL)
133 pos->callback (pos->cls, GNUNET_YES); 247 pos->callback (pos->cls, GNUNET_YES);
134 GNUNET_free (pos); 248 GNUNET_free (pos);
135} 249}
136 250
137 251
252/**
253 * Process a response from ARM to a request for a change in service
254 * status.
255 *
256 * @param cls the request context
257 * @param msg the response
258 */
138static void 259static void
139handle_response (void *cls, const struct GNUNET_MessageHeader *msg) 260handle_response (void *cls, const struct GNUNET_MessageHeader *msg)
140{ 261{
141 struct ArmContext *sc = cls; 262 struct RequestContext *sc = cls;
142 int ret; 263 int ret;
143 264
144 if (msg == NULL) 265 if (msg == NULL)
145 { 266 {
146 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 267 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
147 _("Error receiving response from ARM service\n")); 268 _("Error receiving response from ARM service\n"));
148 GNUNET_CLIENT_disconnect (sc->client); 269 GNUNET_CLIENT_disconnect (sc->h->client);
270 sc->h->client = GNUNET_CLIENT_connect (sc->h->sched,
271 "arm",
272 sc->h->cfg);
273 GNUNET_assert (NULL != sc->h->client);
149 if (sc->callback != NULL) 274 if (sc->callback != NULL)
150 sc->callback (sc->cls, GNUNET_SYSERR); 275 sc->callback (sc->cls, GNUNET_SYSERR);
151 GNUNET_free (sc); 276 GNUNET_free (sc);
@@ -170,73 +295,144 @@ handle_response (void *cls, const struct GNUNET_MessageHeader *msg)
170 GNUNET_break (0); 295 GNUNET_break (0);
171 ret = GNUNET_SYSERR; 296 ret = GNUNET_SYSERR;
172 } 297 }
173 GNUNET_CLIENT_disconnect (sc->client);
174 if (sc->callback != NULL) 298 if (sc->callback != NULL)
175 sc->callback (sc->cls, ret); 299 sc->callback (sc->cls, ret);
176 GNUNET_free (sc); 300 GNUNET_free (sc);
177} 301}
178 302
179 303
304/**
305 * We've failed to transmit the request to the ARM service.
306 * Report our failure and clean up the state.
307 *
308 * @param sctx the state of the (now failed) request
309 */
310static void
311report_transmit_failure (struct RequestContext *sctx)
312{
313 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
314 _("Error while trying to transmit to ARM service\n"));
315 if (sctx->callback != NULL)
316 sctx->callback (sctx->cls, GNUNET_SYSERR);
317 GNUNET_free (sctx);
318}
319
320
321/**
322 * Transmit a request for a service status change to the
323 * ARM service.
324 *
325 * @param cls the "struct RequestContext" identifying the request
326 * @param size how many bytes are available in buf
327 * @param buf where to write the request, NULL on error
328 * @return number of bytes written to buf
329 */
330static size_t
331send_service_msg (void *cls, size_t size, void *buf);
332
333
334/**
335 * We've failed to transmit the request to the ARM service but
336 * are now going to try again.
337 *
338 * @param cls state of the request
339 * @param tc task context (unused)
340 */
341static void
342retry_request (void *cls,
343 const struct GNUNET_SCHEDULER_TaskContext *tc)
344{
345 struct RequestContext *sctx = cls;
346
347 if (NULL ==
348 GNUNET_CLIENT_notify_transmit_ready (sctx->h->client,
349 sctx->slen +
350 sizeof (struct
351 GNUNET_MessageHeader),
352 GNUNET_TIME_absolute_get_remaining (sctx->timeout),
353 &send_service_msg,
354 sctx))
355 {
356 report_transmit_failure (sctx);
357 return;
358 }
359}
360
361
362/**
363 * Transmit a request for a service status change to the
364 * ARM service.
365 *
366 * @param cls the "struct RequestContext" identifying the request
367 * @param size how many bytes are available in buf
368 * @param buf where to write the request, NULL on error
369 * @return number of bytes written to buf
370 */
180static size_t 371static size_t
181send_service_msg (void *cls, size_t size, void *buf) 372send_service_msg (void *cls, size_t size, void *buf)
182{ 373{
183 struct ArmContext *sctx = cls; 374 struct RequestContext *sctx = cls;
184 struct GNUNET_MessageHeader *msg; 375 struct GNUNET_MessageHeader *msg;
185 size_t slen; 376 struct GNUNET_TIME_Relative rem;
186 377
187 if (buf == NULL) 378 if (buf == NULL)
188 { 379 {
189 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 380 GNUNET_CLIENT_disconnect (sctx->h->client);
190 _("Error while trying to transmit to ARM service\n")); 381 sctx->h->client = GNUNET_CLIENT_connect (sctx->h->sched,
191 GNUNET_CLIENT_disconnect (sctx->client); 382 "arm",
192 if (sctx->callback != NULL) 383 sctx->h->cfg);
193 sctx->callback (sctx->cls, GNUNET_SYSERR); 384 GNUNET_assert (sctx->h->client != NULL);
194 GNUNET_free (sctx->service_name); 385 rem = GNUNET_TIME_absolute_get_remaining (sctx->timeout);
195 GNUNET_free (sctx); 386 if ( (sctx->attempts_left-- > 0) &&
387 (rem.value > 0) )
388 {
389 GNUNET_SCHEDULER_add_delayed (sctx->h->sched,
390 GNUNET_NO,
391 GNUNET_SCHEDULER_PRIORITY_KEEP,
392 GNUNET_SCHEDULER_NO_TASK,
393 GNUNET_TIME_relative_min (MIN_RETRY_DELAY,
394 rem),
395 &retry_request,
396 sctx);
397 return 0;
398 }
399 report_transmit_failure (sctx);
196 return 0; 400 return 0;
197 } 401 }
198#if DEBUG_ARM 402#if DEBUG_ARM
199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 403 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
200 _("Transmitting service request to ARM.\n")); 404 _("Transmitting service request to ARM.\n"));
201#endif 405#endif
202 slen = strlen (sctx->service_name) + 1; 406 GNUNET_assert (size >= sctx->slen);
203 GNUNET_assert (size >= slen);
204 msg = buf; 407 msg = buf;
205 msg->size = htons (sizeof (struct GNUNET_MessageHeader) + slen); 408 msg->size = htons (sizeof (struct GNUNET_MessageHeader) + sctx->slen);
206 msg->type = htons (sctx->type); 409 msg->type = htons (sctx->type);
207 memcpy (&msg[1], sctx->service_name, slen); 410 memcpy (&msg[1], sctx->service_name, sctx->slen);
208 GNUNET_free (sctx->service_name); 411 GNUNET_CLIENT_receive (sctx->h->client,
209 sctx->service_name = NULL;
210 GNUNET_CLIENT_receive (sctx->client,
211 &handle_response, 412 &handle_response,
212 sctx, 413 sctx,
213 GNUNET_TIME_absolute_get_remaining (sctx->timeout)); 414 GNUNET_TIME_absolute_get_remaining (sctx->timeout));
214 return slen + sizeof (struct GNUNET_MessageHeader); 415 return sctx->slen + sizeof (struct GNUNET_MessageHeader);
215} 416}
216 417
217 418
218/** 419/**
219 * Start or stop a service. 420 * Start or stop a service.
220 * 421 *
422 * @param h handle to ARM
221 * @param service_name name of the service 423 * @param service_name name of the service
222 * @param cfg configuration to use (needed to contact ARM;
223 * the ARM service may internally use a different
224 * configuration to determine how to start the service).
225 * @param sched scheduler to use
226 * @param timeout how long to wait before failing for good 424 * @param timeout how long to wait before failing for good
227 * @param cb callback to invoke when service is ready 425 * @param cb callback to invoke when service is ready
228 * @param cb_cls closure for callback 426 * @param cb_cls closure for callback
229 * @param type type of the request 427 * @param type type of the request
230 */ 428 */
231static void 429static void
232change_service (const char *service_name, 430change_service (struct GNUNET_ARM_Handle *h,
233 const struct GNUNET_CONFIGURATION_Handle *cfg, 431 const char *service_name,
234 struct GNUNET_SCHEDULER_Handle *sched,
235 struct GNUNET_TIME_Relative timeout, 432 struct GNUNET_TIME_Relative timeout,
236 GNUNET_ARM_Callback cb, void *cb_cls, uint16_t type) 433 GNUNET_ARM_Callback cb, void *cb_cls, uint16_t type)
237{ 434{
238 struct GNUNET_CLIENT_Connection *client; 435 struct RequestContext *sctx;
239 struct ArmContext *sctx;
240 size_t slen; 436 size_t slen;
241 437
242 slen = strlen (service_name) + 1; 438 slen = strlen (service_name) + 1;
@@ -248,128 +444,248 @@ change_service (const char *service_name,
248 cb (cb_cls, GNUNET_NO); 444 cb (cb_cls, GNUNET_NO);
249 return; 445 return;
250 } 446 }
251 client = GNUNET_CLIENT_connect (sched, "arm", cfg);
252 if (client == NULL)
253 {
254 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
255 _("Failed to connect to ARM service\n"));
256 if (cb != NULL)
257 cb (cb_cls, GNUNET_SYSERR);
258 return;
259 }
260#if DEBUG_ARM 447#if DEBUG_ARM
261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
262 _("ARM requests starting of service `%s'.\n"), service_name); 449 _("ARM requests starting of service `%s'.\n"), service_name);
263#endif 450#endif
264 sctx = GNUNET_malloc (sizeof (struct ArmContext)); 451 sctx = GNUNET_malloc (sizeof (struct RequestContext) + slen);
452 sctx->h = h;
265 sctx->callback = cb; 453 sctx->callback = cb;
266 sctx->cls = cb_cls; 454 sctx->cls = cb_cls;
267 sctx->client = client; 455 sctx->service_name = (const char*) &sctx[1];
268 sctx->service_name = GNUNET_strdup (service_name); 456 memcpy (&sctx[1],
457 service_name,
458 slen);
269 sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); 459 sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
460 sctx->slen = slen;
461 sctx->attempts_left = MAX_ATTEMPTS;
270 sctx->type = type; 462 sctx->type = type;
271 if (NULL == 463 retry_request (sctx, NULL);
272 GNUNET_CLIENT_notify_transmit_ready (client,
273 slen +
274 sizeof (struct
275 GNUNET_MessageHeader),
276 timeout, &send_service_msg, sctx))
277 {
278 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
279 _("Failed to transmit request to ARM service\n"));
280 GNUNET_free (sctx->service_name);
281 GNUNET_free (sctx);
282 if (cb != NULL)
283 cb (cb_cls, GNUNET_SYSERR);
284 GNUNET_CLIENT_disconnect (client);
285 return;
286 }
287} 464}
288 465
289 466
290/** 467/**
291 * Start a service. 468 * Start a service.
292 * 469 *
470 * @param h handle to ARM
293 * @param service_name name of the service 471 * @param service_name name of the service
294 * @param cfg configuration to use (needed to contact ARM;
295 * the ARM service may internally use a different
296 * configuration to determine how to start the service).
297 * @param sched scheduler to use
298 * @param timeout how long to wait before failing for good 472 * @param timeout how long to wait before failing for good
299 * @param cb callback to invoke when service is ready 473 * @param cb callback to invoke when service is ready
300 * @param cb_cls closure for callback 474 * @param cb_cls closure for callback
301 */ 475 */
302void 476void
303GNUNET_ARM_start_service (const char *service_name, 477GNUNET_ARM_start_service (struct GNUNET_ARM_Handle *h,
304 const struct GNUNET_CONFIGURATION_Handle *cfg, 478 const char *service_name,
305 struct GNUNET_SCHEDULER_Handle *sched,
306 struct GNUNET_TIME_Relative timeout, 479 struct GNUNET_TIME_Relative timeout,
307 GNUNET_ARM_Callback cb, void *cb_cls) 480 GNUNET_ARM_Callback cb, void *cb_cls)
308{ 481{
309 struct ArmContext *sctx; 482 struct RequestContext *sctx;
310 483
311 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 484 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
312 _("Starting service `%s'\n"), service_name); 485 _("Starting service `%s'\n"), service_name);
313 if (0 == strcmp ("arm", service_name)) 486 if (0 == strcmp ("arm", service_name))
314 { 487 {
315 sctx = GNUNET_malloc (sizeof (struct ArmContext)); 488 sctx = GNUNET_malloc (sizeof (struct RequestContext));
489 sctx->h = h;
316 sctx->callback = cb; 490 sctx->callback = cb;
317 sctx->cls = cb_cls; 491 sctx->cls = cb_cls;
318 sctx->cfg = cfg; 492 sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
319 GNUNET_CLIENT_service_test (sched, 493 GNUNET_CLIENT_service_test (h->sched,
320 "arm", 494 "arm",
321 cfg, timeout, &arm_service_report, sctx); 495 h->cfg, timeout, &arm_service_report, sctx);
322 return; 496 return;
323 } 497 }
324 change_service (service_name, 498 change_service (h, service_name, timeout, cb, cb_cls, GNUNET_MESSAGE_TYPE_ARM_START);
325 cfg,
326 sched, timeout, cb, cb_cls, GNUNET_MESSAGE_TYPE_ARM_START);
327} 499}
328 500
329 501
330
331
332/** 502/**
333 * Stop a service. 503 * Stop a service.
334 * 504 *
505 * @param h handle to ARM
335 * @param service_name name of the service 506 * @param service_name name of the service
336 * @param cfg configuration to use (needed to contact ARM;
337 * the ARM service may internally use a different
338 * configuration to determine how to start the service).
339 * @param sched scheduler to use
340 * @param timeout how long to wait before failing for good 507 * @param timeout how long to wait before failing for good
341 * @param cb callback to invoke when service is ready 508 * @param cb callback to invoke when service is ready
342 * @param cb_cls closure for callback 509 * @param cb_cls closure for callback
343 */ 510 */
344void 511void
345GNUNET_ARM_stop_service (const char *service_name, 512GNUNET_ARM_stop_service (struct GNUNET_ARM_Handle *h,
346 const struct GNUNET_CONFIGURATION_Handle *cfg, 513 const char *service_name,
347 struct GNUNET_SCHEDULER_Handle *sched,
348 struct GNUNET_TIME_Relative timeout, 514 struct GNUNET_TIME_Relative timeout,
349 GNUNET_ARM_Callback cb, void *cb_cls) 515 GNUNET_ARM_Callback cb, void *cb_cls)
350{ 516{
351 struct GNUNET_CLIENT_Connection *client;
352
353 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 517 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
354 _("Stopping service `%s'\n"), service_name); 518 _("Stopping service `%s'\n"), service_name);
355 if (0 == strcmp ("arm", service_name)) 519 if (0 == strcmp ("arm", service_name))
356 { 520 {
357 client = GNUNET_CLIENT_connect (sched, "arm", cfg); 521 GNUNET_CLIENT_service_shutdown (h->client);
358 if (client == NULL)
359 {
360 if (cb != NULL)
361 cb (cb_cls, GNUNET_SYSERR);
362 return;
363 }
364 GNUNET_CLIENT_service_shutdown (client);
365 GNUNET_CLIENT_disconnect (client);
366 if (cb != NULL) 522 if (cb != NULL)
367 cb (cb_cls, GNUNET_NO); 523 cb (cb_cls, GNUNET_NO);
368 return; 524 return;
369 } 525 }
370 change_service (service_name, 526 change_service (h, service_name, timeout, cb, cb_cls, GNUNET_MESSAGE_TYPE_ARM_STOP);
371 cfg,
372 sched, timeout, cb, cb_cls, GNUNET_MESSAGE_TYPE_ARM_STOP);
373} 527}
374 528
529
530/**
531 * Function to call for each service.
532 *
533 * @param h handle to ARM
534 * @param service_name name of the service
535 * @param timeout how long to wait before failing for good
536 * @param cb callback to invoke when service is ready
537 * @param cb_cls closure for callback
538 */
539typedef void (*ServiceOperation) (struct GNUNET_ARM_Handle *h,
540 const char *service_name,
541 struct GNUNET_TIME_Relative timeout,
542 GNUNET_ARM_Callback cb, void *cb_cls);
543
544
545/**
546 * Context for starting or stopping multiple services.
547 */
548struct MultiContext
549{
550 /**
551 * NULL-terminated array of services to start or stop.
552 */
553 char **services;
554
555 /**
556 * Our handle to ARM.
557 */
558 struct GNUNET_ARM_Handle *h;
559
560 /**
561 * Identifies the operation (start or stop).
562 */
563 ServiceOperation op;
564
565 /**
566 * Current position in "services".
567 */
568 unsigned int pos;
569};
570
571
572/**
573 * Run the operation for the next service in the multi-service
574 * request.
575 *
576 * @param cls the "struct MultiContext" that is being processed
577 * @param success status of the previous operation (ignored)
578 */
579static void
580next_operation (void *cls,
581 int success)
582{
583 struct MultiContext *mc = cls;
584 char *pos;
585
586 if (NULL == (pos = mc->services[mc->pos]))
587 {
588 GNUNET_free (mc->services);
589 GNUNET_ARM_disconnect (mc->h);
590 GNUNET_free (mc);
591 return;
592 }
593 mc->pos++;
594 mc->op (mc->h, pos, MULTI_TIMEOUT, &next_operation, mc);
595 GNUNET_free (pos);
596}
597
598
599/**
600 * Run a multi-service request.
601 *
602 * @param cfg configuration to use (needed to contact ARM;
603 * the ARM service may internally use a different
604 * configuration to determine how to start the service).
605 * @param sched scheduler to use
606 * @param op the operation to perform for each service
607 * @param va NULL-terminated list of services
608 */
609static void
610run_multi_request (const struct GNUNET_CONFIGURATION_Handle *cfg,
611 struct GNUNET_SCHEDULER_Handle *sched,
612 ServiceOperation op,
613 va_list va)
614{
615 va_list cp;
616 unsigned int total;
617 struct MultiContext *mc;
618 struct GNUNET_ARM_Handle *h;
619 const char *c;
620
621 h = GNUNET_ARM_connect (cfg, sched, NULL);
622 if (NULL == h)
623 {
624 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
625 _("Error while trying to transmit to ARM service\n"));
626 return;
627 }
628 total = 1;
629 va_copy (cp, va);
630 while (NULL != (va_arg (cp, const char*))) total++;
631 va_end (cp);
632 mc = GNUNET_malloc (sizeof(struct MultiContext));
633 mc->services = GNUNET_malloc (total * sizeof (char*));
634 mc->h = h;
635 mc->op = op;
636 total = 0;
637 va_copy (cp, va);
638 while (NULL != (c = va_arg (cp, const char*)))
639 mc->services[total++] = GNUNET_strdup (c);
640 va_end (cp);
641 next_operation (mc, GNUNET_YES);
642}
643
644
645/**
646 * Start multiple services in the specified order. Convenience
647 * function. Works asynchronously, failures are not reported.
648 *
649 * @param cfg configuration to use (needed to contact ARM;
650 * the ARM service may internally use a different
651 * configuration to determine how to start the service).
652 * @param sched scheduler to use
653 * @param ... NULL-terminated list of service names (const char*)
654 */
655void
656GNUNET_ARM_start_services (const struct GNUNET_CONFIGURATION_Handle *cfg,
657 struct GNUNET_SCHEDULER_Handle *sched,
658 ...)
659{
660 va_list ap;
661
662 va_start (ap, sched);
663 run_multi_request (cfg, sched, &GNUNET_ARM_start_service, ap);
664 va_end (ap);
665}
666
667
668/**
669 * Stop multiple services in the specified order. Convenience
670 * function. Works asynchronously, failures are not reported.
671 *
672 * @param cfg configuration to use (needed to contact ARM;
673 * the ARM service may internally use a different
674 * configuration to determine how to start the service).
675 * @param sched scheduler to use
676 * @param ... NULL-terminated list of service names (const char*)
677 */
678void
679GNUNET_ARM_stop_services (const struct GNUNET_CONFIGURATION_Handle *cfg,
680 struct GNUNET_SCHEDULER_Handle *sched,
681 ...)
682{
683 va_list ap;
684
685 va_start (ap, sched);
686 run_multi_request (cfg, sched, &GNUNET_ARM_stop_service, ap);
687 va_end (ap);
688}
689
690
375/* end of arm_api.c */ 691/* end of arm_api.c */
diff --git a/src/arm/gnunet-arm.c b/src/arm/gnunet-arm.c
index 740fd2533..09a1305a5 100644
--- a/src/arm/gnunet-arm.c
+++ b/src/arm/gnunet-arm.c
@@ -65,7 +65,46 @@ static char *test;
65 */ 65 */
66static int ret; 66static int ret;
67 67
68/**
69 * Connection with ARM.
70 */
71static struct GNUNET_ARM_Handle *h;
72
73/**
74 * Our scheduler.
75 */
76static struct GNUNET_SCHEDULER_Handle *sched;
77
78/**
79 * Our configuration.
80 */
81const struct GNUNET_CONFIGURATION_Handle *cfg;
82
83/**
84 * Processing stage that we are in. Simple counter.
85 */
86static unsigned int phase;
87
68 88
89/**
90 * Main continuation-passing-style loop. Runs the various
91 * jobs that we've been asked to do in order.
92 *
93 * @param cls closure, unused
94 * @param tc context, unused
95 */
96static void
97cps_loop (void *cls,
98 const struct GNUNET_SCHEDULER_TaskContext *tc);
99
100
101/**
102 * Callback invoked with the status of the last operation. Reports to the
103 * user and then runs the next phase in the FSM.
104 *
105 * @param cls pointer to "const char*" identifying service that was manipulated
106 * @param success GNUNET_OK if service is now running, GNUNET_NO if not, GNUNET_SYSERR on error
107 */
69static void 108static void
70confirm_cb (void *cls, int success) 109confirm_cb (void *cls, int success)
71{ 110{
@@ -83,9 +122,21 @@ confirm_cb (void *cls, int success)
83 _("Error updating service `%s': ARM not running\n"), service); 122 _("Error updating service `%s': ARM not running\n"), service);
84 break; 123 break;
85 } 124 }
125 GNUNET_SCHEDULER_add_continuation (sched,
126 GNUNET_NO,
127 &cps_loop,
128 NULL,
129 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
86} 130}
87 131
88 132
133/**
134 * Function called to confirm that a service is running (or that
135 * it is not running).
136 *
137 * @param cls pointer to "const char*" identifying service that was manipulated
138 * @param tc reason determines if service is now running
139 */
89static void 140static void
90confirm_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 141confirm_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
91{ 142{
@@ -95,6 +146,11 @@ confirm_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
95 fprintf (stdout, _("Service `%s' is running.\n"), service); 146 fprintf (stdout, _("Service `%s' is running.\n"), service);
96 else 147 else
97 fprintf (stdout, _("Service `%s' is not running.\n"), service); 148 fprintf (stdout, _("Service `%s' is not running.\n"), service);
149 GNUNET_SCHEDULER_add_continuation (sched,
150 GNUNET_NO,
151 &cps_loop,
152 NULL,
153 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
98} 154}
99 155
100 156
@@ -102,40 +158,90 @@ confirm_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
102 * Main function that will be run by the scheduler. 158 * Main function that will be run by the scheduler.
103 * 159 *
104 * @param cls closure 160 * @param cls closure
105 * @param sched the scheduler to use 161 * @param s the scheduler to use
106 * @param args remaining command-line arguments 162 * @param args remaining command-line arguments
107 * @param cfgfile name of the configuration file used (for saving, can be NULL!) 163 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
108 * @param cfg configuration 164 * @param c configuration
109 */ 165 */
110static void 166static void
111run (void *cls, 167run (void *cls,
112 struct GNUNET_SCHEDULER_Handle *sched, 168 struct GNUNET_SCHEDULER_Handle *s,
113 char *const *args, 169 char *const *args,
114 const char *cfgfile, 170 const char *cfgfile,
115 const struct GNUNET_CONFIGURATION_Handle *cfg) 171 const struct GNUNET_CONFIGURATION_Handle *c)
116{ 172{
117 if (term != NULL) 173 sched = s;
118 { 174 cfg = c;
119 GNUNET_ARM_stop_service (term, cfg, sched, TIMEOUT, &confirm_cb, term); 175 h = GNUNET_ARM_connect (cfg, sched, NULL);
120 } 176 if (h == NULL)
121 if (end)
122 {
123 GNUNET_ARM_stop_service ("arm",
124 cfg, sched, TIMEOUT, &confirm_cb, "arm");
125 }
126 if (start)
127 { 177 {
128 GNUNET_ARM_start_service ("arm", 178 fprintf (stderr,
129 cfg, sched, TIMEOUT, &confirm_cb, "arm"); 179 _("Fatal error initializing ARM API.\n"));
180 ret = 1;
181 return;
130 } 182 }
131 if (init != NULL) 183 GNUNET_SCHEDULER_add_continuation (sched,
132 { 184 GNUNET_NO,
133 GNUNET_ARM_start_service (init, cfg, sched, TIMEOUT, &confirm_cb, init); 185 &cps_loop,
134 } 186 NULL,
135 if (test != NULL) 187 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
188}
189
190
191/**
192 * Main continuation-passing-style loop. Runs the various
193 * jobs that we've been asked to do in order.
194 *
195 * @param cls closure, unused
196 * @param tc context, unused
197 */
198static void
199cps_loop (void *cls,
200 const struct GNUNET_SCHEDULER_TaskContext *tc)
201{
202 while (1)
136 { 203 {
137 GNUNET_CLIENT_service_test (sched, 204 switch (phase++)
138 test, cfg, TIMEOUT, &confirm_task, test); 205 {
206 case 0:
207 if (term != NULL)
208 {
209 GNUNET_ARM_stop_service (h, term, TIMEOUT, &confirm_cb, term);
210 return;
211 }
212 break;
213 case 1:
214 if (end)
215 {
216 GNUNET_ARM_stop_service (h, "arm", TIMEOUT, &confirm_cb, "arm");
217 return;
218 }
219 break;
220 case 2:
221 if (start)
222 {
223 GNUNET_ARM_start_service (h, "arm", TIMEOUT, &confirm_cb, "arm");
224 return;
225 }
226 break;
227 case 3:
228 if (init != NULL)
229 {
230 GNUNET_ARM_start_service (h, init, TIMEOUT, &confirm_cb, init);
231 return;
232 }
233 break;
234 case 4:
235 if (test != NULL)
236 {
237 GNUNET_CLIENT_service_test (sched, test, cfg, TIMEOUT, &confirm_task, test);
238 return;
239 }
240 break;
241 default: /* last phase */
242 GNUNET_ARM_disconnect (h);
243 return;
244 }
139 } 245 }
140} 246}
141 247
diff --git a/src/arm/gnunet-service-arm.c b/src/arm/gnunet-service-arm.c
index c7143e3a7..d43adeae2 100644
--- a/src/arm/gnunet-service-arm.c
+++ b/src/arm/gnunet-service-arm.c
@@ -46,9 +46,15 @@
46 46
47 47
48/** 48/**
49 * Run maintenance every second. 49 * Run normal maintenance every 2s.
50 */ 50 */
51#define MAINT_FREQUENCY GNUNET_TIME_UNIT_SECONDS 51#define MAINT_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2)
52
53/**
54 * Run fast maintenance after 100ms. This is used for an extra-job
55 * that is run to check for a process that we just killed.
56 */
57#define MAINT_FAST_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100)
52 58
53/** 59/**
54 * How long do we wait until we decide that a service 60 * How long do we wait until we decide that a service
@@ -56,8 +62,18 @@
56 */ 62 */
57#define CHECK_TIMEOUT GNUNET_TIME_UNIT_MINUTES 63#define CHECK_TIMEOUT GNUNET_TIME_UNIT_MINUTES
58 64
65/**
66 * List of our services.
67 */
59struct ServiceList; 68struct ServiceList;
60 69
70/**
71 * Function to call if waitpid informs us that
72 * a process has died.
73 *
74 * @param cls closure
75 * @param pos entry in the service list of the process that died
76 */
61typedef void (*CleanCallback) (void *cls, struct ServiceList * pos); 77typedef void (*CleanCallback) (void *cls, struct ServiceList * pos);
62 78
63/** 79/**
@@ -137,6 +153,24 @@ static struct GNUNET_SCHEDULER_Handle *sched;
137static char *prefix_command; 153static char *prefix_command;
138 154
139 155
156/**
157 * Background task doing maintenance.
158 *
159 * @param cls closure, NULL if we need to self-restart
160 * @param tc context
161 */
162static void
163maint (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
164
165
166/**
167 * Transmit a status result message.
168 *
169 * @param cls pointer to "unit16_t*" with message type
170 * @param size number of bytes available in buf
171 * @param buf where to copy the message, NULL on error
172 * @return number of bytes copied to buf
173 */
140static size_t 174static size_t
141write_result (void *cls, size_t size, void *buf) 175write_result (void *cls, size_t size, void *buf)
142{ 176{
@@ -159,6 +193,9 @@ write_result (void *cls, size_t size, void *buf)
159 * Signal our client that we will start or stop the 193 * Signal our client that we will start or stop the
160 * service. 194 * service.
161 * 195 *
196 * @param client who is being signalled
197 * @param name name of the service
198 * @param result message type to send
162 * @return NULL if it was not found 199 * @return NULL if it was not found
163 */ 200 */
164static void 201static void
@@ -188,6 +225,7 @@ signal_result (struct GNUNET_SERVER_Client *client,
188 * Find the process with the given service 225 * Find the process with the given service
189 * name in the given list, remove it and return it. 226 * name in the given list, remove it and return it.
190 * 227 *
228 * @param name which service entry to look up
191 * @return NULL if it was not found 229 * @return NULL if it was not found
192 */ 230 */
193static struct ServiceList * 231static struct ServiceList *
@@ -216,6 +254,11 @@ find_name (const char *name)
216} 254}
217 255
218 256
257/**
258 * Free an entry in the service list.
259 *
260 * @param pos entry to free
261 */
219static void 262static void
220free_entry (struct ServiceList *pos) 263free_entry (struct ServiceList *pos)
221{ 264{
@@ -226,8 +269,6 @@ free_entry (struct ServiceList *pos)
226} 269}
227 270
228 271
229
230
231/** 272/**
232 * Actually start the process for the given service. 273 * Actually start the process for the given service.
233 * 274 *
@@ -335,6 +376,9 @@ start_process (struct ServiceList *sl)
335 376
336/** 377/**
337 * Start the specified service. 378 * Start the specified service.
379 *
380 * @param client who is asking for this
381 * @param servicename name of the service to start
338 */ 382 */
339static void 383static void
340start_service (struct GNUNET_SERVER_Client *client, const char *servicename) 384start_service (struct GNUNET_SERVER_Client *client, const char *servicename)
@@ -394,6 +438,13 @@ start_service (struct GNUNET_SERVER_Client *client, const char *servicename)
394} 438}
395 439
396 440
441/**
442 * Free the given entry in the service list and signal
443 * the given client that the service is now down.
444 *
445 * @param cls pointer to the client ("struct GNUNET_SERVER_Client*")
446 * @param pos entry for the service
447 */
397static void 448static void
398free_and_signal (void *cls, struct ServiceList *pos) 449free_and_signal (void *cls, struct ServiceList *pos)
399{ 450{
@@ -409,9 +460,13 @@ free_and_signal (void *cls, struct ServiceList *pos)
409 460
410/** 461/**
411 * Stop the specified service. 462 * Stop the specified service.
463 *
464 * @param client who is asking for this
465 * @param servicename name of the service to stop
412 */ 466 */
413static void 467static void
414stop_service (struct GNUNET_SERVER_Client *client, const char *servicename) 468stop_service (struct GNUNET_SERVER_Client *client,
469 const char *servicename)
415{ 470{
416 struct ServiceList *pos; 471 struct ServiceList *pos;
417 struct GNUNET_CLIENT_Connection *sc; 472 struct GNUNET_CLIENT_Connection *sc;
@@ -445,6 +500,11 @@ stop_service (struct GNUNET_SERVER_Client *client, const char *servicename)
445 pos->kill_continuation = &free_and_signal; 500 pos->kill_continuation = &free_and_signal;
446 pos->kill_continuation_cls = client; 501 pos->kill_continuation_cls = client;
447 GNUNET_SERVER_client_keep (client); 502 GNUNET_SERVER_client_keep (client);
503 GNUNET_SCHEDULER_add_delayed (sched,
504 GNUNET_YES,
505 GNUNET_SCHEDULER_PRIORITY_IDLE,
506 GNUNET_SCHEDULER_NO_TASK,
507 MAINT_FAST_FREQUENCY, &maint, NULL);
448 } 508 }
449 else 509 else
450 { 510 {
@@ -529,11 +589,10 @@ handle_stop (void *cls,
529} 589}
530 590
531 591
532
533/** 592/**
534 * Background task doing maintenance. 593 * Background task doing maintenance.
535 * 594 *
536 * @param cls closure 595 * @param cls closure, NULL if we need to self-restart
537 * @param tc context 596 * @param tc context
538 */ 597 */
539static void 598static void
@@ -561,11 +620,12 @@ maint (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
561 } 620 }
562 return; 621 return;
563 } 622 }
564 GNUNET_SCHEDULER_add_delayed (tc->sched, 623 if (cls == NULL)
565 GNUNET_YES, 624 GNUNET_SCHEDULER_add_delayed (tc->sched,
566 GNUNET_SCHEDULER_PRIORITY_IDLE, 625 GNUNET_YES,
567 GNUNET_SCHEDULER_NO_TASK, 626 GNUNET_SCHEDULER_PRIORITY_IDLE,
568 MAINT_FREQUENCY, &maint, NULL); 627 GNUNET_SCHEDULER_NO_TASK,
628 MAINT_FREQUENCY, &maint, NULL);
569 629
570 /* check for services that died (WAITPID) */ 630 /* check for services that died (WAITPID) */
571 prev = NULL; 631 prev = NULL;
@@ -656,8 +716,7 @@ maint (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
656 716
657 717
658/** 718/**
659 * List of handlers for the messages understood by this 719 * List of handlers for the messages understood by this service.
660 * service.
661 */ 720 */
662static struct GNUNET_SERVER_MessageHandler handlers[] = { 721static struct GNUNET_SERVER_MessageHandler handlers[] = {
663 {&handle_start, NULL, GNUNET_MESSAGE_TYPE_ARM_START, 0}, 722 {&handle_start, NULL, GNUNET_MESSAGE_TYPE_ARM_START, 0},
diff --git a/src/arm/test_arm_api.c b/src/arm/test_arm_api.c
index fbd90583e..22fa3716e 100644
--- a/src/arm/test_arm_api.c
+++ b/src/arm/test_arm_api.c
@@ -40,17 +40,28 @@ static struct GNUNET_SCHEDULER_Handle *sched;
40 40
41static const struct GNUNET_CONFIGURATION_Handle *cfg; 41static const struct GNUNET_CONFIGURATION_Handle *cfg;
42 42
43static struct GNUNET_ARM_Handle *arm;
44
43static int ok = 1; 45static int ok = 1;
44 46
47
48static void
49arm_notify_stop (void *cls, int success)
50{
51 GNUNET_assert (success == GNUNET_NO);
52#if START_ARM
53 GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, NULL, NULL);
54#endif
55}
56
57
45static void 58static void
46dns_notify (void *cls, const struct sockaddr *addr, socklen_t addrlen) 59dns_notify (void *cls, const struct sockaddr *addr, socklen_t addrlen)
47{ 60{
48 if (addr == NULL) 61 if (addr == NULL)
49 { 62 {
50 GNUNET_assert (ok == 0); 63 GNUNET_assert (ok == 0);
51#if START_ARM 64 GNUNET_ARM_stop_service (arm, "resolver", TIMEOUT, &arm_notify_stop, NULL);
52 GNUNET_ARM_stop_service ("arm", cfg, sched, TIMEOUT, NULL, NULL);
53#endif
54 return; 65 return;
55 } 66 }
56 GNUNET_assert (addr != NULL); 67 GNUNET_assert (addr != NULL);
@@ -62,21 +73,17 @@ static void
62resolver_notify (void *cls, int success) 73resolver_notify (void *cls, int success)
63{ 74{
64 GNUNET_assert (success == GNUNET_YES); 75 GNUNET_assert (success == GNUNET_YES);
65 sleep (1); /* FIXME: that we need to do this is a problem... */
66 GNUNET_RESOLVER_ip_get (sched, 76 GNUNET_RESOLVER_ip_get (sched,
67 cfg, 77 cfg,
68 "localhost", AF_INET, TIMEOUT, &dns_notify, NULL); 78 "localhost", AF_INET, TIMEOUT, &dns_notify, NULL);
69} 79}
70 80
81
71static void 82static void
72arm_notify (void *cls, int success) 83arm_notify (void *cls, int success)
73{ 84{
74 GNUNET_assert (success == GNUNET_YES); 85 GNUNET_assert (success == GNUNET_YES);
75#if START_ARM 86 GNUNET_ARM_start_service (arm, "resolver", TIMEOUT, &resolver_notify, NULL);
76 sleep (1); /* FIXME: that we need to do this is a problem... */
77#endif
78 GNUNET_ARM_start_service ("resolver",
79 cfg, sched, TIMEOUT, &resolver_notify, NULL);
80} 87}
81 88
82 89
@@ -89,8 +96,9 @@ task (void *cls,
89{ 96{
90 cfg = c; 97 cfg = c;
91 sched = s; 98 sched = s;
99 arm = GNUNET_ARM_connect (cfg, sched, NULL);
92#if START_ARM 100#if START_ARM
93 GNUNET_ARM_start_service ("arm", cfg, sched, TIMEOUT, &arm_notify, NULL); 101 GNUNET_ARM_start_service (arm, "arm", TIMEOUT, &arm_notify, NULL);
94#else 102#else
95 arm_notify (NULL, GNUNET_YES); 103 arm_notify (NULL, GNUNET_YES);
96#endif 104#endif
diff --git a/src/core/test_core_api.c b/src/core/test_core_api.c
index 13c1dc48e..d72af8254 100644
--- a/src/core/test_core_api.c
+++ b/src/core/test_core_api.c
@@ -82,8 +82,8 @@ terminate_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
82 GNUNET_CORE_disconnect (p2.ch); 82 GNUNET_CORE_disconnect (p2.ch);
83 GNUNET_TRANSPORT_disconnect (p1.th); 83 GNUNET_TRANSPORT_disconnect (p1.th);
84 GNUNET_TRANSPORT_disconnect (p2.th); 84 GNUNET_TRANSPORT_disconnect (p2.th);
85 GNUNET_ARM_stop_service ("core", p1.cfg, sched, TIMEOUT, NULL, NULL); 85 GNUNET_ARM_stop_services (p1.cfg, sched, "core", NULL);
86 GNUNET_ARM_stop_service ("core", p2.cfg, sched, TIMEOUT, NULL, NULL); 86 GNUNET_ARM_stop_services (p2.cfg, sched, "core", NULL);
87 ok = 0; 87 ok = 0;
88} 88}
89 89
@@ -96,8 +96,8 @@ terminate_task_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
96 GNUNET_CORE_disconnect (p2.ch); 96 GNUNET_CORE_disconnect (p2.ch);
97 GNUNET_TRANSPORT_disconnect (p1.th); 97 GNUNET_TRANSPORT_disconnect (p1.th);
98 GNUNET_TRANSPORT_disconnect (p2.th); 98 GNUNET_TRANSPORT_disconnect (p2.th);
99 GNUNET_ARM_stop_service ("core", p1.cfg, sched, TIMEOUT, NULL, NULL); 99 GNUNET_ARM_stop_services (p1.cfg, sched, "core", NULL);
100 GNUNET_ARM_stop_service ("core", p2.cfg, sched, TIMEOUT, NULL, NULL); 100 GNUNET_ARM_stop_services (p2.cfg, sched, "core", NULL);
101 ok = 42; 101 ok = 42;
102} 102}
103 103
@@ -303,7 +303,7 @@ setup_peer (struct PeerContext *p, const char *cfgname)
303 sleep (1); /* allow ARM to start */ 303 sleep (1); /* allow ARM to start */
304#endif 304#endif
305 GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); 305 GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
306 GNUNET_ARM_start_service ("core", p->cfg, sched, TIMEOUT, NULL, NULL); 306 GNUNET_ARM_start_services (p->cfg, sched, "core", NULL);
307 p->th = GNUNET_TRANSPORT_connect (sched, p->cfg, p, NULL, NULL, NULL); 307 p->th = GNUNET_TRANSPORT_connect (sched, p->cfg, p, NULL, NULL, NULL);
308 GNUNET_assert (p->th != NULL); 308 GNUNET_assert (p->th != NULL);
309 GNUNET_TRANSPORT_get_hello (p->th, TIMEOUT, &process_hello, p); 309 GNUNET_TRANSPORT_get_hello (p->th, TIMEOUT, &process_hello, p);
diff --git a/src/core/test_core_api_start_only.c b/src/core/test_core_api_start_only.c
index d0a5aedc4..ce2668b89 100644
--- a/src/core/test_core_api_start_only.c
+++ b/src/core/test_core_api_start_only.c
@@ -147,8 +147,8 @@ init_notify (void *cls,
147 GNUNET_assert (cls == &p2); 147 GNUNET_assert (cls == &p2);
148 GNUNET_CORE_disconnect (p1.ch); 148 GNUNET_CORE_disconnect (p1.ch);
149 GNUNET_CORE_disconnect (p2.ch); 149 GNUNET_CORE_disconnect (p2.ch);
150 GNUNET_ARM_stop_service ("core", p1.cfg, sched, TIMEOUT, NULL, NULL); 150 GNUNET_ARM_stop_services (p1.cfg, sched, "core", NULL);
151 GNUNET_ARM_stop_service ("core", p2.cfg, sched, TIMEOUT, NULL, NULL); 151 GNUNET_ARM_stop_services (p2.cfg, sched, "core", NULL);
152 152
153 ok = 0; 153 ok = 0;
154 } 154 }
@@ -169,7 +169,7 @@ setup_peer (struct PeerContext *p, const char *cfgname)
169 sleep (1); /* allow ARM to start */ 169 sleep (1); /* allow ARM to start */
170#endif 170#endif
171 GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); 171 GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
172 GNUNET_ARM_start_service ("core", p->cfg, sched, TIMEOUT, NULL, NULL); 172 GNUNET_ARM_start_services (p->cfg, sched, "core", NULL);
173} 173}
174 174
175 175
diff --git a/src/include/gnunet_arm_service.h b/src/include/gnunet_arm_service.h
index bbb8cb0f6..8e68cd5ee 100644
--- a/src/include/gnunet_arm_service.h
+++ b/src/include/gnunet_arm_service.h
@@ -58,45 +58,111 @@ typedef void (*GNUNET_ARM_Callback) (void *cls, int success);
58 58
59 59
60/** 60/**
61 * Start a service. 61 * Handle for interacting with ARM.
62 */
63struct GNUNET_ARM_Handle;
64
65
66/**
67 * Setup a context for communicating with ARM. Note that this
68 * can be done even if the ARM service is not yet running.
62 * 69 *
63 * @param service_name name of the service
64 * @param cfg configuration to use (needed to contact ARM; 70 * @param cfg configuration to use (needed to contact ARM;
65 * the ARM service may internally use a different 71 * the ARM service may internally use a different
66 * configuration to determine how to start the service). 72 * configuration to determine how to start the service).
67 * @param sched scheduler to use 73 * @param sched scheduler to use
74 * @param service service that *this* process is implementing/providing, can be NULL
75 * @return context to use for further ARM operations, NULL on error
76 */
77struct GNUNET_ARM_Handle *
78GNUNET_ARM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
79 struct GNUNET_SCHEDULER_Handle *sched,
80 const char *service);
81
82
83/**
84 * Disconnect from the ARM service.
85 *
86 * @param h the handle that was being used
87 */
88void
89GNUNET_ARM_disconnect (struct GNUNET_ARM_Handle *h);
90
91
92/**
93 * Start a service. Note that this function merely asks ARM to start
94 * the service and that ARM merely confirms that it forked the
95 * respective process. The specified callback may thus return before
96 * the service has started to listen on the server socket and it may
97 * also be that the service has crashed in the meantime. Clients
98 * should repeatedly try to connect to the service at the respective
99 * port (with some delays in between) before assuming that the service
100 * actually failed to start. Note that if an error is returned to the
101 * callback, clients obviously should not bother with trying to
102 * contact the service.
103 *
104 * @param h handle to ARM
105 * @param service_name name of the service
68 * @param timeout how long to wait before failing for good 106 * @param timeout how long to wait before failing for good
69 * @param cb callback to invoke when service is ready 107 * @param cb callback to invoke when service is ready
70 * @param cb_cls closure for callback 108 * @param cb_cls closure for callback
71 */ 109 */
72void 110void
73GNUNET_ARM_start_service (const char *service_name, 111GNUNET_ARM_start_service (struct GNUNET_ARM_Handle *h,
74 const struct GNUNET_CONFIGURATION_Handle *cfg, 112 const char *service_name,
75 struct GNUNET_SCHEDULER_Handle *sched,
76 struct GNUNET_TIME_Relative timeout, 113 struct GNUNET_TIME_Relative timeout,
77 GNUNET_ARM_Callback cb, void *cb_cls); 114 GNUNET_ARM_Callback cb, void *cb_cls);
78 115
79 116
80/** 117/**
81 * Stop a service. 118 * Stop a service. Note that the callback is invoked as soon
119 * as ARM confirms that it will ask the service to terminate.
120 * The actual termination may still take some time.
82 * 121 *
122 * @param h handle to ARM
83 * @param service_name name of the service 123 * @param service_name name of the service
84 * @param cfg configuration to use (needed to contact ARM;
85 * the ARM service may internally use a different
86 * configuration to determine how to start the service).
87 * @param sched scheduler to use
88 * @param timeout how long to wait before failing for good 124 * @param timeout how long to wait before failing for good
89 * @param cb callback to invoke when service is ready 125 * @param cb callback to invoke when service is ready
90 * @param cb_cls closure for callback 126 * @param cb_cls closure for callback
91 */ 127 */
92void 128void
93GNUNET_ARM_stop_service (const char *service_name, 129GNUNET_ARM_stop_service (struct GNUNET_ARM_Handle *h,
94 const struct GNUNET_CONFIGURATION_Handle *cfg, 130 const char *service_name,
95 struct GNUNET_SCHEDULER_Handle *sched,
96 struct GNUNET_TIME_Relative timeout, 131 struct GNUNET_TIME_Relative timeout,
97 GNUNET_ARM_Callback cb, void *cb_cls); 132 GNUNET_ARM_Callback cb, void *cb_cls);
98 133
99 134
135/**
136 * Start multiple services in the specified order. Convenience
137 * function. Works asynchronously, failures are not reported.
138 *
139 * @param cfg configuration to use (needed to contact ARM;
140 * the ARM service may internally use a different
141 * configuration to determine how to start the service).
142 * @param sched scheduler to use
143 * @param ... NULL-terminated list of service names (const char*)
144 */
145void
146GNUNET_ARM_start_services (const struct GNUNET_CONFIGURATION_Handle *cfg,
147 struct GNUNET_SCHEDULER_Handle *sched,
148 ...);
149
150
151/**
152 * Stop multiple services in the specified order. Convenience
153 * function. Works asynchronously, failures are not reported.
154 *
155 * @param cfg configuration to use (needed to contact ARM;
156 * the ARM service may internally use a different
157 * configuration to determine how to start the service).
158 * @param sched scheduler to use
159 * @param ... NULL-terminated list of service names (const char*)
160 */
161void
162GNUNET_ARM_stop_services (const struct GNUNET_CONFIGURATION_Handle *cfg,
163 struct GNUNET_SCHEDULER_Handle *sched,
164 ...);
165
100 166
101#if 0 /* keep Emacsens' auto-indent happy */ 167#if 0 /* keep Emacsens' auto-indent happy */
102{ 168{
diff --git a/src/testing/testing.c b/src/testing/testing.c
index a82842777..4bdad178f 100644
--- a/src/testing/testing.c
+++ b/src/testing/testing.c
@@ -49,9 +49,8 @@
49#define ARM_START_WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) 49#define ARM_START_WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
50 50
51/** 51/**
52 * How many times are we willing to try to 52 * How many times are we willing to try to wait for "scp" or
53 * wait for "scp" or "gnunet-service-arm" to 53 * "gnunet-service-arm" to complete (waitpid) before giving up?
54 * complete (waitpid) before giving up?
55 */ 54 */
56#define MAX_EXEC_WAIT_RUNS 50 55#define MAX_EXEC_WAIT_RUNS 50
57 56
@@ -60,12 +59,39 @@
60 */ 59 */
61enum StartPhase 60enum StartPhase
62 { 61 {
62 /**
63 * FIXME.
64 */
63 SP_COPYING, 65 SP_COPYING,
66
67 /**
68 * FIXME.
69 */
64 SP_COPIED, 70 SP_COPIED,
71
72 /**
73 * FIXME.
74 */
65 SP_START_ARMING, 75 SP_START_ARMING,
76
77 /**
78 * FIXME.
79 */
66 SP_START_CORE, 80 SP_START_CORE,
81
82 /**
83 * FIXME.
84 */
67 SP_START_DONE, 85 SP_START_DONE,
86
87 /**
88 * FIXME.
89 */
68 SP_CLEANUP, 90 SP_CLEANUP,
91
92 /**
93 * FIXME.
94 */
69 SP_CONFIG_UPDATE 95 SP_CONFIG_UPDATE
70 }; 96 };
71 97
@@ -839,21 +865,56 @@ void GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d,
839 d); 865 d);
840} 866}
841 867
842 868/**
869 * FIXME.
870 */
843struct ConnectContext 871struct ConnectContext
844{ 872{
873 /**
874 * FIXME.
875 */
845 struct GNUNET_TESTING_Daemon *d1; 876 struct GNUNET_TESTING_Daemon *d1;
877
878 /**
879 * FIXME.
880 */
846 struct GNUNET_TESTING_Daemon *d2; 881 struct GNUNET_TESTING_Daemon *d2;
882
883 /**
884 * FIXME.
885 */
847 struct GNUNET_TRANSPORT_Handle *d1th; 886 struct GNUNET_TRANSPORT_Handle *d1th;
887
888 /**
889 * FIXME.
890 */
848 struct GNUNET_TRANSPORT_Handle *d2th; 891 struct GNUNET_TRANSPORT_Handle *d2th;
892
893 /**
894 * When should this operation be complete (or we must trigger
895 * a timeout).
896 */
849 struct GNUNET_TIME_Absolute timeout; 897 struct GNUNET_TIME_Absolute timeout;
898
899 /**
900 * Function to call once we are done (or have timed out).
901 */
850 GNUNET_TESTING_NotifyCompletion cb; 902 GNUNET_TESTING_NotifyCompletion cb;
903
904 /**
905 * Closure for "nb".
906 */
851 void *cb_cls; 907 void *cb_cls;
852}; 908};
853 909
854 910
855/** 911/**
856 * Success, connection is up. Signal client our success. 912 * Success, connection is up. Signal client our success.
913 *
914 * @param cls FIXME
915 * @param size number of bytes available in buf
916 * @param buf where to copy the message, NULL on error
917 * @return number of bytes copied to buf
857 */ 918 */
858static size_t 919static size_t
859transmit_ready (void *cls, size_t size, void *buf) 920transmit_ready (void *cls, size_t size, void *buf)
diff --git a/src/transport/transport_api.c b/src/transport/transport_api.c
index b1b8ce445..9a7068e42 100644
--- a/src/transport/transport_api.c
+++ b/src/transport/transport_api.c
@@ -1458,10 +1458,7 @@ GNUNET_TRANSPORT_connect (struct GNUNET_SCHEDULER_Handle *sched,
1458{ 1458{
1459 struct GNUNET_TRANSPORT_Handle *ret; 1459 struct GNUNET_TRANSPORT_Handle *ret;
1460 1460
1461 GNUNET_ARM_start_service ("peerinfo", 1461 GNUNET_ARM_start_services (cfg, sched, "peerinfo", "transport", NULL);
1462 cfg, sched, START_SERVICE_TIMEOUT, NULL, NULL);
1463 GNUNET_ARM_start_service ("transport",
1464 cfg, sched, START_SERVICE_TIMEOUT, NULL, NULL);
1465 ret = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_Handle)); 1462 ret = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_Handle));
1466 ret->sched = sched; 1463 ret->sched = sched;
1467 ret->cfg = cfg; 1464 ret->cfg = cfg;
@@ -1483,12 +1480,8 @@ static void
1483stop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 1480stop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1484{ 1481{
1485 struct GNUNET_TRANSPORT_Handle *handle = cls; 1482 struct GNUNET_TRANSPORT_Handle *handle = cls;
1486 GNUNET_ARM_stop_service ("transport", 1483
1487 handle->cfg, 1484 GNUNET_ARM_stop_services (handle->cfg, handle->sched, "transport", "peerinfo", NULL);
1488 tc->sched, STOP_SERVICE_TIMEOUT, NULL, NULL);
1489 GNUNET_ARM_stop_service ("peerinfo",
1490 handle->cfg,
1491 tc->sched, STOP_SERVICE_TIMEOUT, NULL, NULL);
1492} 1485}
1493 1486
1494 1487