aboutsummaryrefslogtreecommitdiff
path: root/src/arm/test_exponential_backoff.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-06-29 17:05:12 +0000
committerChristian Grothoff <christian@grothoff.org>2016-06-29 17:05:12 +0000
commitdb62b73f216cbf6c955e6f1b9eceffa7beae7339 (patch)
treed2f09591a7d87bce4c565956e01a7b0cdf5238f9 /src/arm/test_exponential_backoff.c
parentf37a1330954a757525a34ebecc074412e66d7fe8 (diff)
downloadgnunet-db62b73f216cbf6c955e6f1b9eceffa7beae7339.tar.gz
gnunet-db62b73f216cbf6c955e6f1b9eceffa7beae7339.zip
-convert backoff test to new MQ API
Diffstat (limited to 'src/arm/test_exponential_backoff.c')
-rw-r--r--src/arm/test_exponential_backoff.c322
1 files changed, 114 insertions, 208 deletions
diff --git a/src/arm/test_exponential_backoff.c b/src/arm/test_exponential_backoff.c
index 8135f5157..ab47ff635 100644
--- a/src/arm/test_exponential_backoff.c
+++ b/src/arm/test_exponential_backoff.c
@@ -20,6 +20,7 @@
20/** 20/**
21 * @file arm/test_exponential_backoff.c 21 * @file arm/test_exponential_backoff.c
22 * @brief testcase for gnunet-service-arm.c 22 * @brief testcase for gnunet-service-arm.c
23 * @author Christian Grothoff
23 */ 24 */
24#include "platform.h" 25#include "platform.h"
25#include "gnunet_arm_service.h" 26#include "gnunet_arm_service.h"
@@ -28,8 +29,6 @@
28 29
29#define LOG(...) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__) 30#define LOG(...) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
30 31
31#define START_ARM GNUNET_YES
32
33#define LOG_BACKOFF GNUNET_NO 32#define LOG_BACKOFF GNUNET_NO
34 33
35#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) 34#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
@@ -51,6 +50,8 @@ static struct GNUNET_ARM_Handle *arm;
51 50
52static struct GNUNET_ARM_MonitorHandle *mon; 51static struct GNUNET_ARM_MonitorHandle *mon;
53 52
53static struct GNUNET_SCHEDULER_Task *kt;
54
54static int ok = 1; 55static int ok = 1;
55 56
56static int phase = 0; 57static int phase = 0;
@@ -70,10 +71,6 @@ static char *killLogFileName;
70#endif 71#endif
71 72
72 73
73typedef void
74(*GNUNET_CLIENT_ShutdownTask) (void *cls, int reason);
75
76
77/** 74/**
78 * Context for handling the shutdown of a service. 75 * Context for handling the shutdown of a service.
79 */ 76 */
@@ -82,210 +79,94 @@ struct ShutdownContext
82 /** 79 /**
83 * Connection to the service that is being shutdown. 80 * Connection to the service that is being shutdown.
84 */ 81 */
85 struct GNUNET_CLIENT_Connection *sock; 82 struct GNUNET_MQ_Handle *mq;
86
87 /**
88 * Time allowed for shutdown to happen.
89 */
90 struct GNUNET_TIME_Absolute timeout;
91 83
92 /** 84 /**
93 * Task set up to cancel the shutdown request on timeout. 85 * Task set up to cancel the shutdown request on timeout.
94 */ 86 */
95 struct GNUNET_SCHEDULER_Task *cancel_task; 87 struct GNUNET_SCHEDULER_Task *cancel_task;
96 88
97 /** 89};
98 * Task to call once shutdown complete
99 */
100 GNUNET_CLIENT_ShutdownTask cont;
101 90
102 /**
103 * Closure for shutdown continuation
104 */
105 void *cont_cls;
106 91
107 /** 92static void
108 * We received a confirmation that the service will shut down. 93kill_task (void *cbData);
109 */
110 int confirmed;
111 94
112};
113 95
114/** 96/**
115 * Handler receiving response to service shutdown requests. 97 * Shutting down took too long, cancel receive and return error.
116 * We expect it to be called with NULL, since the service that
117 * we are shutting down will just die without replying.
118 * 98 *
119 * @param cls closure 99 * @param cls closure
120 * @param msg NULL, indicating socket closure.
121 */ 100 */
122static void 101static void
123service_shutdown_handler (void *cls, 102service_shutdown_timeout (void *cls)
124 const struct GNUNET_MessageHeader *msg)
125{ 103{
126 struct ShutdownContext *shutdown_ctx = cls;
127
128 if (NULL == msg)
129 {
130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service shutdown complete.\n");
131 if (shutdown_ctx->cont != NULL)
132 shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_NO);
133
134 GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task);
135 GNUNET_CLIENT_disconnect (shutdown_ctx->sock);
136 GNUNET_free (shutdown_ctx);
137 return;
138 }
139 GNUNET_assert (0); 104 GNUNET_assert (0);
140} 105}
141 106
142 107
143/** 108/**
144 * Shutting down took too long, cancel receive and return error. 109 * Generic error handler, called with the appropriate error code and
110 * the same closure specified at the creation of the message queue.
111 * Not every message queue implementation supports an error handler.
145 * 112 *
146 * @param cls closure 113 * @param cls closure with the `struct ShutdownContext *`
114 * @param error error code
147 */ 115 */
148static void 116static void
149service_shutdown_cancel (void *cls) 117mq_error_handler (void *cls,
118 enum GNUNET_MQ_Error error)
150{ 119{
151 struct ShutdownContext *shutdown_ctx = cls; 120 struct ShutdownContext *shutdown_ctx = cls;
152 121
153 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
154 "service_shutdown_cancel called!\n"); 123 "Service shutdown complete (MQ error).\n");
155 shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_SYSERR); 124 GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task);
156 GNUNET_CLIENT_disconnect (shutdown_ctx->sock); 125 GNUNET_MQ_destroy (shutdown_ctx->mq);
157 GNUNET_free (shutdown_ctx); 126 GNUNET_free (shutdown_ctx);
158} 127}
159 128
160 129
161/**
162 * If possible, write a shutdown message to the target
163 * buffer and destroy the client connection.
164 *
165 * @param cls the "struct GNUNET_CLIENT_Connection" to destroy
166 * @param size number of bytes available in buf
167 * @param buf NULL on error, otherwise target buffer
168 * @return number of bytes written to buf
169 */
170static size_t
171write_shutdown (void *cls, size_t size, void *buf)
172{
173 struct GNUNET_MessageHeader *msg;
174 struct ShutdownContext *shutdown_ctx = cls;
175
176 if (size < sizeof (struct GNUNET_MessageHeader))
177 {
178 LOG ("Failed to send a shutdown request\n");
179 shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_SYSERR);
180 GNUNET_CLIENT_disconnect (shutdown_ctx->sock);
181 GNUNET_free (shutdown_ctx);
182 return 0; /* client disconnected */
183 }
184
185 GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler,
186 shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL);
187 shutdown_ctx->cancel_task = GNUNET_SCHEDULER_add_delayed (
188 GNUNET_TIME_absolute_get_remaining (shutdown_ctx->timeout),
189 &service_shutdown_cancel, shutdown_ctx);
190 msg = (struct GNUNET_MessageHeader *) buf;
191 msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_STOP);
192 msg->size = htons (sizeof (struct GNUNET_MessageHeader));
193 strcpy ((char *) &msg[1], SERVICE);
194 LOG ("Sent a shutdown request\n");
195 return sizeof (struct GNUNET_MessageHeader) + strlen (SERVICE) + 1;
196}
197
198
199/**
200 * Request that the service should shutdown.
201 * Afterwards, the connection will automatically be
202 * disconnected. Hence the "sock" should not
203 * be used by the caller after this call
204 * (calling this function frees "sock" after a while).
205 *
206 * @param sock the socket connected to the service
207 * @param timeout how long to wait before giving up on transmission
208 * @param cont continuation to call once the service is really down
209 * @param cont_cls closure for continuation
210 *
211 */
212static void
213do_nothing_service_shutdown (struct GNUNET_CLIENT_Connection *sock,
214 struct GNUNET_TIME_Relative timeout,
215 GNUNET_CLIENT_ShutdownTask cont,
216 void *cont_cls)
217{
218 struct ShutdownContext *shutdown_ctx;
219
220 shutdown_ctx = GNUNET_new (struct ShutdownContext);
221 shutdown_ctx->cont = cont;
222 shutdown_ctx->cont_cls = cont_cls;
223 shutdown_ctx->sock = sock;
224 shutdown_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
225 GNUNET_CLIENT_notify_transmit_ready (sock,
226 sizeof (struct GNUNET_MessageHeader) + strlen (SERVICE) + 1,
227 timeout, GNUNET_NO, &write_shutdown,
228 shutdown_ctx);
229}
230
231
232static void
233kill_task (void *cbData);
234
235
236static void
237shutdown_cont (void *cls, int reason)
238{
239 if (GNUNET_NO != reason)
240 {
241 /* Re-try shutdown */
242 LOG ("do-nothing didn't die, trying again\n");
243 GNUNET_SCHEDULER_add_now (&kill_task, NULL);
244 return;
245 }
246 startedWaitingAt = GNUNET_TIME_absolute_get ();
247 LOG ("do-nothing is dead, starting the countdown\n");
248}
249
250
251static void 130static void
252kill_task (void *cbData) 131kill_task (void *cbData)
253{ 132{
254 static struct GNUNET_CLIENT_Connection *doNothingConnection = NULL; 133 struct ShutdownContext *shutdown_ctx
134 = GNUNET_new (struct ShutdownContext);
135 struct GNUNET_MQ_Envelope *env;
136 struct GNUNET_MessageHeader *msg;
137 struct GNUNET_MQ_MessageHandler handlers[] = {
138 GNUNET_MQ_handler_end ()
139 };
255 140
256 if (NULL != cbData) 141 kt = NULL;
142 if (trialCount == 13)
257 { 143 {
258 waitedFor = GNUNET_TIME_absolute_get_duration (startedWaitingAt); 144 LOG ("Saw enough kills, asking ARM to stop mock service for good\n");
259 LOG ("Waited for: %s\n",
260 GNUNET_STRINGS_relative_time_to_string (waitedFor, GNUNET_YES));
261 }
262 else
263 {
264 waitedFor.rel_value_us = 0;
265 }
266 /* Connect to the doNothing task */
267 doNothingConnection = GNUNET_CLIENT_connect (SERVICE, cfg);
268 GNUNET_assert (doNothingConnection != NULL);
269 if (trialCount == 12)
270 waitedFor_prev = waitedFor;
271 else if (trialCount == 13)
272 {
273 GNUNET_CLIENT_disconnect (doNothingConnection);
274 GNUNET_ARM_request_service_stop (arm, 145 GNUNET_ARM_request_service_stop (arm,
275 SERVICE, 146 SERVICE,
276 NULL, 147 NULL,
277 NULL); 148 NULL);
278 if (waitedFor_prev.rel_value_us >= waitedFor.rel_value_us) 149 ok = 0;
279 ok = 9; 150 trialCount++;
280 else 151 GNUNET_free (shutdown_ctx);
281 ok = 0;
282 trialCount += 1;
283 return; 152 return;
284 } 153 }
285 trialCount += 1; 154 shutdown_ctx->mq = GNUNET_CLIENT_connecT (cfg,
286 /* Use the created connection to kill the doNothingTask */ 155 SERVICE,
287 do_nothing_service_shutdown (doNothingConnection, 156 handlers,
288 TIMEOUT, &shutdown_cont, NULL); 157 &mq_error_handler,
158 shutdown_ctx);
159 GNUNET_assert (NULL != shutdown_ctx->mq);
160 trialCount++;
161 LOG ("Sending a shutdown request to the mock service\n");
162 env = GNUNET_MQ_msg (msg,
163 GNUNET_MESSAGE_TYPE_ARM_STOP); /* FIXME: abuse of message type */
164 GNUNET_MQ_send (shutdown_ctx->mq,
165 env);
166 shutdown_ctx->cancel_task
167 = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
168 &service_shutdown_timeout,
169 shutdown_ctx);
289} 170}
290 171
291 172
@@ -294,6 +175,11 @@ trigger_disconnect (void *cls)
294{ 175{
295 GNUNET_ARM_disconnect (arm); 176 GNUNET_ARM_disconnect (arm);
296 GNUNET_ARM_monitor_stop (mon); 177 GNUNET_ARM_monitor_stop (mon);
178 if (NULL != kt)
179 {
180 GNUNET_SCHEDULER_cancel (kt);
181 kt = NULL;
182 }
297} 183}
298 184
299 185
@@ -305,7 +191,7 @@ arm_stop_cb (void *cls,
305 GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK); 191 GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK);
306 GNUNET_break (result == GNUNET_ARM_RESULT_STOPPED); 192 GNUNET_break (result == GNUNET_ARM_RESULT_STOPPED);
307 LOG ("ARM service stopped\n"); 193 LOG ("ARM service stopped\n");
308 GNUNET_SCHEDULER_add_now (&trigger_disconnect, NULL); 194 GNUNET_SCHEDULER_shutdown ();
309} 195}
310 196
311 197
@@ -314,9 +200,9 @@ srv_status (void *cls,
314 const char *service, 200 const char *service,
315 enum GNUNET_ARM_ServiceStatus status) 201 enum GNUNET_ARM_ServiceStatus status)
316{ 202{
317 LOG ("Service %s is %u, phase %u\n", service, status, phase);
318 if (status == GNUNET_ARM_SERVICE_MONITORING_STARTED) 203 if (status == GNUNET_ARM_SERVICE_MONITORING_STARTED)
319 { 204 {
205 LOG ("ARM monitor started, starting mock service\n");
320 phase++; 206 phase++;
321 GNUNET_ARM_request_service_start (arm, 207 GNUNET_ARM_request_service_start (arm,
322 SERVICE, 208 SERVICE,
@@ -325,31 +211,42 @@ srv_status (void *cls,
325 NULL); 211 NULL);
326 return; 212 return;
327 } 213 }
214 if (0 != strcasecmp (service, SERVICE))
215 return; /* not what we care about */
328 if (phase == 1) 216 if (phase == 1)
329 { 217 {
330 GNUNET_break (status == GNUNET_ARM_SERVICE_STARTING); 218 GNUNET_break (status == GNUNET_ARM_SERVICE_STARTING);
331 GNUNET_break (0 == strcasecmp (service, SERVICE));
332 GNUNET_break (phase == 1); 219 GNUNET_break (phase == 1);
333 LOG ("do-nothing is starting\n"); 220 LOG ("do-nothing is starting\n");
334 phase++; 221 phase++;
335 ok = 1; 222 ok = 1;
336 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, 223 GNUNET_assert (NULL == kt);
337 &kill_task, 224 startedWaitingAt = GNUNET_TIME_absolute_get ();
338 NULL); 225 kt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
226 &kill_task,
227 NULL);
339 } 228 }
340 else if ((phase == 2) && (strcasecmp (SERVICE, service) == 0)) 229 else if (phase == 2)
341 { 230 {
342 /* We passively monitor ARM for status updates. ARM should tell us 231 /* We passively monitor ARM for status updates. ARM should tell us
343 * when do-nothing dies (no need to run a service upness test ourselves). 232 * when do-nothing dies (no need to run a service upness test ourselves).
344 */ 233 */
345 if (status == GNUNET_ARM_SERVICE_STARTING) 234 if (status == GNUNET_ARM_SERVICE_STARTING)
346 { 235 {
347 LOG ("do-nothing is starting\n"); 236 waitedFor = GNUNET_TIME_absolute_get_duration (startedWaitingAt);
348 GNUNET_SCHEDULER_add_now (&kill_task, &ok); 237 LOG ("Waited for: %s\n",
238 GNUNET_STRINGS_relative_time_to_string (waitedFor,
239 GNUNET_YES));
240
241 LOG ("do-nothing is starting, killing it...\n");
242 GNUNET_assert (NULL == kt);
243 kt = GNUNET_SCHEDULER_add_now (&kill_task, &ok);
349 } 244 }
350 else if ((status == GNUNET_ARM_SERVICE_STOPPED) && (trialCount == 14)) 245 else if ((status == GNUNET_ARM_SERVICE_STOPPED) && (trialCount == 14))
351 { 246 {
352 phase++; 247 phase++;
248 LOG ("do-nothing stopped working %u times, we are done here\n",
249 (unsigned int) trialCount);
353 GNUNET_ARM_request_service_stop (arm, 250 GNUNET_ARM_request_service_stop (arm,
354 "arm", 251 "arm",
355 &arm_stop_cb, 252 &arm_stop_cb,
@@ -380,30 +277,28 @@ task (void *cls,
380{ 277{
381 cfg = c; 278 cfg = c;
382 arm = GNUNET_ARM_connect (cfg, NULL, NULL); 279 arm = GNUNET_ARM_connect (cfg, NULL, NULL);
383 if (NULL != arm) 280 if (NULL == arm)
384 { 281 {
385 mon = GNUNET_ARM_monitor_start (cfg, &srv_status, NULL); 282 GNUNET_break (0);
386 if (NULL != mon) 283 return;
387 { 284 }
388#if START_ARM 285 mon = GNUNET_ARM_monitor_start (cfg,
389 GNUNET_ARM_request_service_start (arm, 286 &srv_status,
390 "arm", 287 NULL);
391 GNUNET_OS_INHERIT_STD_OUT_AND_ERR, 288 if (NULL == mon)
392 &arm_start_cb, 289 {
393 NULL); 290 GNUNET_break (0);
394#else 291 GNUNET_ARM_disconnect (arm);
395 arm_start_cb (NULL, 292 arm = NULL;
396 arm, 293 return;
397 GNUNET_ARM_REQUEST_SENT_OK,
398 GNUNET_ARM_SERVICE_STARTING);
399#endif
400 }
401 else
402 {
403 GNUNET_ARM_disconnect (arm);
404 arm = NULL;
405 }
406 } 294 }
295 GNUNET_ARM_request_service_start (arm,
296 "arm",
297 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
298 &arm_start_cb,
299 NULL);
300 GNUNET_SCHEDULER_add_shutdown (&trigger_disconnect,
301 NULL);
407} 302}
408 303
409 304
@@ -422,10 +317,12 @@ check ()
422 /* Running ARM and running the do_nothing task */ 317 /* Running ARM and running the do_nothing task */
423 GNUNET_assert (GNUNET_OK == 318 GNUNET_assert (GNUNET_OK ==
424 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, 319 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
425 argv, "test-exponential-backoff", 320 argv,
426 "nohelp", options, &task, NULL)); 321 "test-exponential-backoff",
427 322 "nohelp",
428 323 options,
324 &task,
325 NULL));
429 return ok; 326 return ok;
430} 327}
431 328
@@ -451,10 +348,17 @@ init ()
451 return GNUNET_SYSERR; 348 return GNUNET_SYSERR;
452 if (NULL == getcwd (pwd, PATH_MAX)) 349 if (NULL == getcwd (pwd, PATH_MAX))
453 return GNUNET_SYSERR; 350 return GNUNET_SYSERR;
454 GNUNET_assert (0 < GNUNET_asprintf (&binary, "%s/%s", pwd, BINARY)); 351 GNUNET_assert (0 < GNUNET_asprintf (&binary,
455 GNUNET_CONFIGURATION_set_value_string (cfg, SERVICE, "BINARY", binary); 352 "%s/%s",
353 pwd,
354 BINARY));
355 GNUNET_CONFIGURATION_set_value_string (cfg,
356 SERVICE,
357 "BINARY",
358 binary);
456 GNUNET_free (binary); 359 GNUNET_free (binary);
457 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, CFGFILENAME)) 360 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg,
361 CFGFILENAME))
458 { 362 {
459 GNUNET_CONFIGURATION_destroy (cfg); 363 GNUNET_CONFIGURATION_destroy (cfg);
460 return GNUNET_SYSERR; 364 return GNUNET_SYSERR;
@@ -463,9 +367,11 @@ init ()
463 367
464#if LOG_BACKOFF 368#if LOG_BACKOFF
465 killLogFileName = GNUNET_DISK_mktemp ("exponential-backoff-waiting.log"); 369 killLogFileName = GNUNET_DISK_mktemp ("exponential-backoff-waiting.log");
466 if (NULL == (killLogFilePtr = FOPEN (killLogFileName, "w"))) 370 if (NULL == (killLogFilePtr = FOPEN (killLogFileName,
371 "w")))
467 { 372 {
468 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "fopen", 373 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
374 "fopen",
469 killLogFileName); 375 killLogFileName);
470 GNUNET_free (killLogFileName); 376 GNUNET_free (killLogFileName);
471 return GNUNET_SYSERR; 377 return GNUNET_SYSERR;