2 This file is part of GNUnet.
3 Copyright (C) 2009, 2016 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
21 * @file arm/test_exponential_backoff.c
22 * @brief testcase for gnunet-service-arm.c
23 * @author Christian Grothoff
26 #include "gnunet_arm_service.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_protocols.h"
30 #define LOG(...) GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
32 #define LOG_BACKOFF GNUNET_NO
34 #define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10)
36 #define SERVICE_TEST_TIMEOUT GNUNET_TIME_UNIT_FOREVER_REL
38 #define FIVE_MILLISECONDS GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 5)
40 #define SERVICE "do-nothing"
42 #define BINARY "mockup-service"
44 #define CFGFILENAME "test_arm_api_data2.conf"
47 static const struct GNUNET_CONFIGURATION_Handle *cfg;
49 static struct GNUNET_ARM_Handle *arm;
51 static struct GNUNET_ARM_MonitorHandle *mon;
53 static struct GNUNET_SCHEDULER_Task *kt;
59 static int trialCount;
61 static struct GNUNET_TIME_Absolute startedWaitingAt;
63 struct GNUNET_TIME_Relative waitedFor;
65 struct GNUNET_TIME_Relative waitedFor_prev;
68 static FILE *killLogFilePtr;
70 static char *killLogFileName;
75 * Context for handling the shutdown of a service.
77 struct ShutdownContext {
79 * Connection to the service that is being shutdown.
81 struct GNUNET_MQ_Handle *mq;
84 * Task set up to cancel the shutdown request on timeout.
86 struct GNUNET_SCHEDULER_Task *cancel_task;
91 kill_task(void *cbData);
95 * Shutting down took too long, cancel receive and return error.
100 service_shutdown_timeout(void *cls)
107 * Generic error handler, called with the appropriate error code and
108 * the same closure specified at the creation of the message queue.
109 * Not every message queue implementation supports an error handler.
111 * @param cls closure with the `struct ShutdownContext *`
112 * @param error error code
115 mq_error_handler(void *cls,
116 enum GNUNET_MQ_Error error)
118 struct ShutdownContext *shutdown_ctx = cls;
120 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
121 "Service shutdown complete (MQ error).\n");
122 GNUNET_SCHEDULER_cancel(shutdown_ctx->cancel_task);
123 GNUNET_MQ_destroy(shutdown_ctx->mq);
124 GNUNET_free(shutdown_ctx);
129 kill_task(void *cbData)
131 struct ShutdownContext *shutdown_ctx
132 = GNUNET_new(struct ShutdownContext);
133 struct GNUNET_MQ_Envelope *env;
134 struct GNUNET_MessageHeader *msg;
135 struct GNUNET_MQ_MessageHandler handlers[] = {
136 GNUNET_MQ_handler_end()
140 if (trialCount == 13)
142 LOG("Saw enough kills, asking ARM to stop mock service for good\n");
143 GNUNET_ARM_request_service_stop(arm,
149 GNUNET_free(shutdown_ctx);
152 shutdown_ctx->mq = GNUNET_CLIENT_connect(cfg,
157 GNUNET_assert(NULL != shutdown_ctx->mq);
159 LOG("Sending a shutdown request to the mock service\n");
160 env = GNUNET_MQ_msg(msg,
161 GNUNET_MESSAGE_TYPE_ARM_STOP); /* FIXME: abuse of message type */
162 GNUNET_MQ_send(shutdown_ctx->mq,
164 shutdown_ctx->cancel_task
165 = GNUNET_SCHEDULER_add_delayed(TIMEOUT,
166 &service_shutdown_timeout,
172 trigger_disconnect(void *cls)
174 GNUNET_ARM_disconnect(arm);
175 GNUNET_ARM_monitor_stop(mon);
178 GNUNET_SCHEDULER_cancel(kt);
185 arm_stop_cb(void *cls,
186 enum GNUNET_ARM_RequestStatus status,
187 enum GNUNET_ARM_Result result)
189 GNUNET_break(status == GNUNET_ARM_REQUEST_SENT_OK);
190 GNUNET_break(result == GNUNET_ARM_RESULT_STOPPED);
191 LOG("ARM service stopped\n");
192 GNUNET_SCHEDULER_shutdown();
197 srv_status(void *cls,
199 enum GNUNET_ARM_ServiceMonitorStatus status)
201 if (status == GNUNET_ARM_SERVICE_MONITORING_STARTED)
203 LOG("ARM monitor started, starting mock service\n");
205 GNUNET_ARM_request_service_start(arm,
207 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
212 if (0 != strcasecmp(service, SERVICE))
213 return; /* not what we care about */
216 GNUNET_break(status == GNUNET_ARM_SERVICE_STARTING);
217 GNUNET_break(phase == 1);
218 LOG("do-nothing is starting\n");
221 GNUNET_assert(NULL == kt);
222 startedWaitingAt = GNUNET_TIME_absolute_get();
223 kt = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_SECONDS,
229 /* We passively monitor ARM for status updates. ARM should tell us
230 * when do-nothing dies (no need to run a service upness test ourselves).
232 if (status == GNUNET_ARM_SERVICE_STARTING)
234 waitedFor = GNUNET_TIME_absolute_get_duration(startedWaitingAt);
235 LOG("Waited for: %s\n",
236 GNUNET_STRINGS_relative_time_to_string(waitedFor,
239 LOG("do-nothing is starting, killing it...\n");
240 GNUNET_assert(NULL == kt);
241 kt = GNUNET_SCHEDULER_add_now(&kill_task, &ok);
243 else if ((status == GNUNET_ARM_SERVICE_STOPPED) && (trialCount == 14))
246 LOG("do-nothing stopped working %u times, we are done here\n",
247 (unsigned int)trialCount);
248 GNUNET_ARM_request_service_stop(arm,
258 arm_start_cb(void *cls,
259 enum GNUNET_ARM_RequestStatus status,
260 enum GNUNET_ARM_Result result)
262 GNUNET_break(status == GNUNET_ARM_REQUEST_SENT_OK);
263 GNUNET_break(result == GNUNET_ARM_RESULT_STARTING);
264 GNUNET_break(phase == 0);
265 LOG("Sent 'START' request for arm to ARM %s\n",
266 (status == GNUNET_ARM_REQUEST_SENT_OK) ? "successfully" : "unsuccessfully");
274 const struct GNUNET_CONFIGURATION_Handle *c)
277 arm = GNUNET_ARM_connect(cfg, NULL, NULL);
283 mon = GNUNET_ARM_monitor_start(cfg,
289 GNUNET_ARM_disconnect(arm);
293 GNUNET_ARM_request_service_start(arm,
295 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
298 GNUNET_SCHEDULER_add_shutdown(&trigger_disconnect,
306 char *const argv[] = {
307 "test-exponential-backoff",
311 struct GNUNET_GETOPT_CommandLineOption options[] = {
312 GNUNET_GETOPT_OPTION_END
315 /* Running ARM and running the do_nothing task */
316 GNUNET_assert(GNUNET_OK ==
317 GNUNET_PROGRAM_run((sizeof(argv) / sizeof(char *)) - 1,
319 "test-exponential-backoff",
330 * Assumed maximum path length (for the log file name).
332 #define PATH_MAX 4096
339 struct GNUNET_CONFIGURATION_Handle *cfg;
343 cfg = GNUNET_CONFIGURATION_create();
344 if (GNUNET_OK != GNUNET_CONFIGURATION_parse(cfg,
345 "test_arm_api_data.conf"))
347 GNUNET_CONFIGURATION_destroy(cfg);
348 return GNUNET_SYSERR;
350 if (NULL == getcwd(pwd, PATH_MAX))
351 return GNUNET_SYSERR;
352 GNUNET_assert(0 < GNUNET_asprintf(&binary,
356 GNUNET_CONFIGURATION_set_value_string(cfg,
361 if (GNUNET_OK != GNUNET_CONFIGURATION_write(cfg,
364 GNUNET_CONFIGURATION_destroy(cfg);
365 return GNUNET_SYSERR;
367 GNUNET_CONFIGURATION_destroy(cfg);
370 killLogFileName = GNUNET_DISK_mktemp("exponential-backoff-waiting.log");
371 if (NULL == (killLogFilePtr = fopen(killLogFileName,
374 GNUNET_log_strerror_file(GNUNET_ERROR_TYPE_WARNING,
377 GNUNET_free(killLogFileName);
378 return GNUNET_SYSERR;
389 GNUNET_assert(0 == fclose(killLogFilePtr));
390 GNUNET_free(killLogFileName);
392 (void)unlink(CFGFILENAME);
397 main(int argc, char *argv[])
401 GNUNET_log_setup("test-exponential-backoff",
405 if (GNUNET_OK != init())
412 /* end of test_exponential_backoff.c */