aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authort3sserakt <t3ss@posteo.de>2021-07-07 10:40:07 +0200
committert3sserakt <t3ss@posteo.de>2021-07-07 10:40:07 +0200
commit48cc7d6cbc9552794e846200deaf679714ffa4eb (patch)
tree477d9f5223af2c4a586a20351e60be1c519663af
parentd0d24c62f4b4a1872c8b52ad902b11aa4962d2c2 (diff)
downloadgnunet-48cc7d6cbc9552794e846200deaf679714ffa4eb.tar.gz
gnunet-48cc7d6cbc9552794e846200deaf679714ffa4eb.zip
- added rudimentary cmd helper (copied from testbed-helper), binary to start a testcase plugin, rudimentary testcase plugin
-rw-r--r--src/include/gnunet_testing_plugin.h60
-rw-r--r--src/testbed/Makefile.am32
-rw-r--r--src/testbed/gnunet-cmd.c93
-rw-r--r--src/testbed/gnunet-helper-cmds.c581
-rw-r--r--src/testbed/plugin_testcmd.c87
-rw-r--r--src/testbed/testbed_api.h5
-rw-r--r--src/testbed/testbed_api_cmd_netjail_start_testbed.c7
-rw-r--r--src/testing/testing_api_loop.c47
8 files changed, 899 insertions, 13 deletions
diff --git a/src/include/gnunet_testing_plugin.h b/src/include/gnunet_testing_plugin.h
new file mode 100644
index 000000000..527f509ad
--- /dev/null
+++ b/src/include/gnunet_testing_plugin.h
@@ -0,0 +1,60 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
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.
9
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.
14
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/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 *
23 * @author t3sserakt
24 *
25 * Plugin API to start test cases.
26 *
27 */
28#ifndef GNUNET_TESTING_PLUGIN_H
29#define GNUNET_TESTING_PLUGIN_H
30
31#ifdef __cplusplus
32extern "C"
33{
34#if 0 /* keep Emacsens' auto-indent happy */
35}
36#endif
37#endif
38
39
40typedef void
41(*GNUNET_TESTING_PLUGIN_StartTestCase) ();
42
43struct GNUNET_TESTING_PluginFunctions
44{
45 /**
46 * Closure for all of the callbacks.
47 */
48 void *cls;
49
50 GNUNET_TESTING_PLUGIN_StartTestCase start_testcase;
51};
52
53#if 0 /* keep Emacsens' auto-indent happy */
54{
55#endif
56#ifdef __cplusplus
57}
58#endif
59
60#endif
diff --git a/src/testbed/Makefile.am b/src/testbed/Makefile.am
index 79989bae7..8c4a6342b 100644
--- a/src/testbed/Makefile.am
+++ b/src/testbed/Makefile.am
@@ -6,6 +6,8 @@ if USE_COVERAGE
6 XLIB = -lgcov 6 XLIB = -lgcov
7endif 7endif
8 8
9plugindir = $(libdir)/gnunet
10
9libexecdir= $(pkglibdir)/libexec/ 11libexecdir= $(pkglibdir)/libexec/
10 12
11pkgcfgdir= $(pkgdatadir)/config.d/ 13pkgcfgdir= $(pkgdatadir)/config.d/
@@ -21,6 +23,8 @@ if HAVE_SQLITE
21endif 23endif
22 24
23libexec_PROGRAMS = \ 25libexec_PROGRAMS = \
26 gnunet-cmd \
27 gnunet-helper-cmds \
24 gnunet-service-testbed \ 28 gnunet-service-testbed \
25 gnunet-helper-testbed \ 29 gnunet-helper-testbed \
26 gnunet-daemon-testbed-blacklist \ 30 gnunet-daemon-testbed-blacklist \
@@ -33,6 +37,18 @@ bin_PROGRAMS = \
33noinst_PROGRAMS = \ 37noinst_PROGRAMS = \
34 $(generate_underlay) 38 $(generate_underlay)
35 39
40plugin_LTLIBRARIES = \
41 libgnunet_plugin_testcmd.la
42
43libgnunet_plugin_testcmd_la_SOURCES = \
44 plugin_testcmd.c
45libgnunet_plugin_testcmd_la_LIBADD = \
46 $(top_builddir)/src/util/libgnunetutil.la \
47 $(top_builddir)/src/testing/libgnunettesting.la \
48 $(LTLIBINTL)
49libgnunet_plugin_testcmd_la_LDFLAGS = \
50 $(GN_PLUGIN_LDFLAGS)
51
36gnunet_service_testbed_SOURCES = \ 52gnunet_service_testbed_SOURCES = \
37 gnunet-service-testbed.c gnunet-service-testbed.h \ 53 gnunet-service-testbed.c gnunet-service-testbed.h \
38 gnunet-service-testbed_links.c gnunet-service-testbed_links.h \ 54 gnunet-service-testbed_links.c gnunet-service-testbed_links.h \
@@ -70,6 +86,22 @@ gnunet_helper_testbed_LDADD = $(XLIB) \
70 libgnunettestbed.la \ 86 libgnunettestbed.la \
71 $(LTLIBINTL) $(Z_LIBS) 87 $(LTLIBINTL) $(Z_LIBS)
72 88
89gnunet_cmd_SOURCES = \
90 gnunet-cmd.c
91gnunet_cmd_LDADD = $(XLIB) \
92 $(top_builddir)/src/util/libgnunetutil.la \
93 $(top_builddir)/src/testing/libgnunettesting.la \
94 libgnunettestbed.la \
95 $(LTLIBINTL) $(Z_LIBS)
96
97gnunet_helper_cmds_SOURCES = \
98 gnunet-helper-cmds.c
99gnunet_helper_cmds_LDADD = $(XLIB) \
100 $(top_builddir)/src/util/libgnunetutil.la \
101 $(top_builddir)/src/testing/libgnunettesting.la \
102 libgnunettestbed.la \
103 $(LTLIBINTL) $(Z_LIBS)
104
73gnunet_daemon_testbed_blacklist_SOURCES = gnunet-daemon-testbed-blacklist.c 105gnunet_daemon_testbed_blacklist_SOURCES = gnunet-daemon-testbed-blacklist.c
74gnunet_daemon_testbed_blacklist_LDADD = $(XLIB) \ 106gnunet_daemon_testbed_blacklist_LDADD = $(XLIB) \
75 $(top_builddir)/src/transport/libgnunettransport.la \ 107 $(top_builddir)/src/transport/libgnunettransport.la \
diff --git a/src/testbed/gnunet-cmd.c b/src/testbed/gnunet-cmd.c
new file mode 100644
index 000000000..477c3c454
--- /dev/null
+++ b/src/testbed/gnunet-cmd.c
@@ -0,0 +1,93 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013, 2016 GNUnet e.V.
4
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.
9
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.
14
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/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/gnunet-cmd.c
23 *
24 * @brief Binary to start testcase plugins
25 *
26 * @author t3sserakt
27 */
28
29#include "platform.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_testing_lib.h"
32#include "gnunet_testing_plugin.h"
33
34/**
35 * Generic logging shortcut
36 */
37#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
38
39
40/**
41 * Handle for a plugin.
42 */
43struct Plugin
44{
45 /**
46 * Name of the shared library.
47 */
48 char *library_name;
49
50 /**
51 * Plugin API.
52 */
53 struct GNUNET_TESTING_PluginFunctions *api;
54};
55
56
57/**
58 * Main function to run the test cases.
59 *
60 * @param cls not used.
61 *
62 */
63static void
64run (void *cls)
65{
66 struct Plugin *plugin;
67
68 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "gnunet-cmd",
69 "running plugin.\n");
70 LOG (GNUNET_ERROR_TYPE_ERROR,
71 "running plugin.\n");
72 plugin = GNUNET_new (struct Plugin);
73 plugin->api = GNUNET_PLUGIN_load ("libgnunet_plugin_testcmd",
74 NULL);
75 plugin->library_name = GNUNET_strdup ("libgnunet_plugin_testcmd");
76 plugin->api->start_testcase ();
77}
78
79
80int
81main (int argc, char *const *argv)
82{
83 int rv = 0;
84
85 GNUNET_log_setup ("gnunet-cmd",
86 "DEBUG",
87 NULL);
88
89 GNUNET_SCHEDULER_run (&run,
90 NULL);
91
92 return rv;
93}
diff --git a/src/testbed/gnunet-helper-cmds.c b/src/testbed/gnunet-helper-cmds.c
new file mode 100644
index 000000000..3073ebdfb
--- /dev/null
+++ b/src/testbed/gnunet-helper-cmds.c
@@ -0,0 +1,581 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013, 2016 GNUnet e.V.
4
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.
9
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.
14
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/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/gnunet-helper-cmds.c
23 * @brief Helper binary that is started from a remote interpreter loop to start
24 * a local interpreter loop.
25 *
26 * This helper monitors for three termination events. They are: (1)The
27 * stdin of the helper is closed for reading; (2)the helper received
28 * SIGTERM/SIGINT; (3)the local loop crashed. In case of events 1 and 2
29 * the helper kills the interpreter loop. When the interpreter loop
30 * crashed (event 3), the helper should send a SIGTERM to its own process
31 * group; this behaviour will help terminate any child processes the loop
32 * has started and prevents them from leaking and running forever.
33 *
34 * @author t3sserakt
35 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
36 */
37
38
39#include "platform.h"
40#include "gnunet_util_lib.h"
41#include "gnunet_testing_lib.h"
42#include "gnunet_testbed_service.h"
43#include "testbed_helper.h"
44#include "testbed_api.h"
45#include <zlib.h>
46
47/**
48 * Generic logging shortcut
49 */
50#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
51
52/**
53 * Debug logging shorthand
54 */
55#define LOG_DEBUG(...) LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
56
57
58/**
59 * Context for a single write on a chunk of memory
60 */
61struct WriteContext
62{
63 /**
64 * The data to write
65 */
66 void *data;
67
68 /**
69 * The length of the data
70 */
71 size_t length;
72
73 /**
74 * The current position from where the write operation should begin
75 */
76 size_t pos;
77};
78
79/**
80 * The process handle to the testbed service
81 */
82static struct GNUNET_OS_Process *cmd_binary_process;
83
84/**
85 * Handle to the testing system
86 */
87static struct GNUNET_TESTING_System *test_system;
88
89/**
90 * Our message stream tokenizer
91 */
92struct GNUNET_MessageStreamTokenizer *tokenizer;
93
94/**
95 * Disk handle from stdin
96 */
97static struct GNUNET_DISK_FileHandle *stdin_fd;
98
99/**
100 * Disk handle for stdout
101 */
102static struct GNUNET_DISK_FileHandle *stdout_fd;
103
104/**
105 * Pipe used to communicate shutdown via signal.
106 */
107static struct GNUNET_DISK_PipeHandle *sigpipe;
108
109/**
110 * Task identifier for the read task
111 */
112static struct GNUNET_SCHEDULER_Task *read_task_id;
113
114/**
115 * Task identifier for the write task
116 */
117static struct GNUNET_SCHEDULER_Task *write_task_id;
118
119/**
120 * Task to kill the child
121 */
122static struct GNUNET_SCHEDULER_Task *child_death_task_id;
123
124/**
125 * Are we done reading messages from stdin?
126 */
127static int done_reading;
128
129/**
130 * Result to return in case we fail
131 */
132static int status;
133
134
135/**
136 * Task to shut down cleanly
137 *
138 * @param cls NULL
139 */
140static void
141shutdown_task (void *cls)
142{
143 LOG_DEBUG ("Shutting down\n");
144
145 if (NULL != read_task_id)
146 {
147 GNUNET_SCHEDULER_cancel (read_task_id);
148 read_task_id = NULL;
149 }
150 if (NULL != write_task_id)
151 {
152 struct WriteContext *wc;
153
154 wc = GNUNET_SCHEDULER_cancel (write_task_id);
155 write_task_id = NULL;
156 GNUNET_free (wc->data);
157 GNUNET_free (wc);
158 }
159 if (NULL != child_death_task_id)
160 {
161 GNUNET_SCHEDULER_cancel (child_death_task_id);
162 child_death_task_id = NULL;
163 }
164 if (NULL != stdin_fd)
165 (void) GNUNET_DISK_file_close (stdin_fd);
166 if (NULL != stdout_fd)
167 (void) GNUNET_DISK_file_close (stdout_fd);
168 GNUNET_MST_destroy (tokenizer);
169 tokenizer = NULL;
170
171 if (NULL != test_system)
172 {
173 GNUNET_TESTING_system_destroy (test_system, GNUNET_YES);
174 test_system = NULL;
175 }
176}
177
178
179/**
180 * Task to write to the standard out
181 *
182 * @param cls the WriteContext
183 */
184static void
185write_task (void *cls)
186{
187 struct WriteContext *wc = cls;
188 ssize_t bytes_wrote;
189
190 GNUNET_assert (NULL != wc);
191 write_task_id = NULL;
192 bytes_wrote = GNUNET_DISK_file_write (stdout_fd,
193 wc->data + wc->pos,
194 wc->length - wc->pos);
195 if (GNUNET_SYSERR == bytes_wrote)
196 {
197 LOG (GNUNET_ERROR_TYPE_WARNING, "Cannot reply back configuration\n");
198 GNUNET_free (wc->data);
199 GNUNET_free (wc);
200 return;
201 }
202 wc->pos += bytes_wrote;
203 if (wc->pos == wc->length)
204 {
205 GNUNET_free (wc->data);
206 GNUNET_free (wc);
207 return;
208 }
209 write_task_id = GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
210 stdout_fd,
211 &write_task,
212 wc);
213}
214
215
216/**
217 * Task triggered whenever we receive a SIGCHLD (child
218 * process died).
219 *
220 * @param cls closure, NULL if we need to self-restart
221 */
222static void
223child_death_task (void *cls)
224{
225 const struct GNUNET_DISK_FileHandle *pr;
226 char c[16];
227
228 pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
229 child_death_task_id = NULL;
230 /* consume the signal */
231 GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof(c)));
232 LOG_DEBUG ("Got SIGCHLD\n");
233
234 LOG_DEBUG ("Child hasn't died. Resuming to monitor its status\n");
235 child_death_task_id =
236 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
237 pr,
238 &child_death_task,
239 NULL);
240}
241
242
243/**
244 * Functions with this signature are called whenever a
245 * complete message is received by the tokenizer.
246 *
247 * Do not call #GNUNET_mst_destroy() in this callback
248 *
249 * @param cls identification of the client
250 * @param message the actual message
251 * @return #GNUNET_OK on success,
252 * #GNUNET_NO to stop further processing (no error)
253 * #GNUNET_SYSERR to stop further processing with error
254 */
255static int
256tokenizer_cb (void *cls, const struct GNUNET_MessageHeader *message)
257{
258 const struct GNUNET_TESTBED_HelperInit *msg;
259 struct GNUNET_TESTBED_HelperReply *reply;
260 struct GNUNET_CONFIGURATION_Handle *cfg;
261 struct WriteContext *wc;
262 char *binary;
263 char *trusted_ip;
264 char *hostname;
265 char *config;
266 char *xconfig;
267 char *evstr;
268 // char *str;
269 size_t config_size;
270 uLongf ul_config_size;
271 size_t xconfig_size;
272 uint16_t trusted_ip_size;
273 uint16_t hostname_size;
274 uint16_t msize;
275
276 msize = ntohs (message->size);
277 if ((sizeof(struct GNUNET_TESTBED_HelperInit) >= msize) ||
278 (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_INIT != ntohs (message->type)))
279 {
280 LOG (GNUNET_ERROR_TYPE_WARNING, "Received unexpected message -- exiting\n");
281 goto error;
282 }
283 msg = (const struct GNUNET_TESTBED_HelperInit *) message;
284 trusted_ip_size = ntohs (msg->trusted_ip_size);
285 trusted_ip = (char *) &msg[1];
286 if ('\0' != trusted_ip[trusted_ip_size])
287 {
288 LOG (GNUNET_ERROR_TYPE_WARNING, "Trusted IP cannot be empty -- exiting\n");
289 goto error;
290 }
291 hostname_size = ntohs (msg->hostname_size);
292 if ((sizeof(struct GNUNET_TESTBED_HelperInit) + trusted_ip_size + 1
293 + hostname_size) >= msize)
294 {
295 GNUNET_break (0);
296 LOG (GNUNET_ERROR_TYPE_WARNING, "Received unexpected message -- exiting\n");
297 goto error;
298 }
299 ul_config_size = (uLongf) ntohs (msg->config_size);
300 config = GNUNET_malloc (ul_config_size);
301 xconfig_size = msize - (trusted_ip_size + 1 + hostname_size
302 + sizeof(struct GNUNET_TESTBED_HelperInit));
303 int ret = uncompress ((Bytef *) config,
304 &ul_config_size,
305 (const Bytef *) (trusted_ip + trusted_ip_size + 1
306 + hostname_size),
307 (uLongf) xconfig_size);
308 if (Z_OK != ret)
309 {
310 switch (ret)
311 {
312 case Z_MEM_ERROR:
313 LOG (GNUNET_ERROR_TYPE_ERROR, "Not enough memory for decompression\n");
314 break;
315
316 case Z_BUF_ERROR:
317 LOG (GNUNET_ERROR_TYPE_ERROR, "Output buffer too small\n");
318 break;
319
320 case Z_DATA_ERROR:
321 LOG (GNUNET_ERROR_TYPE_ERROR, "Data corrupted/incomplete\n");
322 break;
323
324 default:
325 GNUNET_break (0);
326 }
327 LOG (GNUNET_ERROR_TYPE_ERROR,
328 "Error while uncompressing config -- exiting\n");
329 GNUNET_free (config);
330 goto error;
331 }
332 cfg = GNUNET_CONFIGURATION_create ();
333 if (GNUNET_OK !=
334 GNUNET_CONFIGURATION_deserialize (cfg, config, ul_config_size, NULL))
335 {
336 LOG (GNUNET_ERROR_TYPE_ERROR, "Unable to deserialize config -- exiting\n");
337 GNUNET_free (config);
338 goto error;
339 }
340 GNUNET_free (config);
341 hostname = NULL;
342 if (0 != hostname_size)
343 {
344 hostname = GNUNET_malloc (hostname_size + 1);
345 GNUNET_strlcpy (hostname,
346 ((char *) &msg[1]) + trusted_ip_size + 1,
347 hostname_size + 1);
348 }
349 /* unset GNUNET_TESTING_PREFIX if present as it is more relevant for testbed */
350 evstr = getenv (GNUNET_TESTING_PREFIX);
351 if (NULL != evstr)
352 {
353 /* unsetting the variable will invalidate the pointer! */
354 evstr = GNUNET_strdup (evstr);
355 GNUNET_break (0 == unsetenv (GNUNET_TESTING_PREFIX));
356 }
357 test_system =
358 GNUNET_TESTING_system_create ("testbed-helper", trusted_ip, hostname, NULL);
359 if (NULL != evstr)
360 {
361 char *evar;
362
363 GNUNET_asprintf (&evar, GNUNET_TESTING_PREFIX "=%s", evstr);
364 GNUNET_assert (0 == putenv (evar)); /* consumes 'evar',
365 see putenv(): becomes part of environment! */
366 GNUNET_free (evstr);
367 evstr = NULL;
368 }
369 GNUNET_free (hostname);
370 hostname = NULL;
371 GNUNET_assert (NULL != test_system);
372 GNUNET_assert (GNUNET_OK ==
373 GNUNET_TESTING_configuration_create (test_system, cfg));
374 GNUNET_assert (GNUNET_OK ==
375 GNUNET_CONFIGURATION_get_value_filename (cfg,
376 "PATHS",
377 "DEFAULTCONFIG",
378 &config));
379 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config))
380 {
381 LOG (GNUNET_ERROR_TYPE_WARNING,
382 "Unable to write config file: %s -- exiting\n",
383 config);
384 GNUNET_CONFIGURATION_destroy (cfg);
385 GNUNET_free (config);
386 goto error;
387 }
388 LOG_DEBUG ("Staring testbed with config: %s\n", config);
389 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-cmd");
390 {
391 char *evar;
392
393 /* expose testbed configuration through env variable */
394 GNUNET_asprintf (&evar, "%s=%s", ENV_TESTBED_CONFIG, config);
395 GNUNET_assert (0 == putenv (evar)); /* consumes 'evar',
396 see putenv(): becomes part of environment! */
397 evstr = NULL;
398 }
399
400 cmd_binary_process = GNUNET_OS_start_process (
401 GNUNET_OS_INHERIT_STD_ERR /*verbose? */,
402 NULL,
403 NULL,
404 NULL,
405 binary);
406
407 if (NULL == cmd_binary_process)
408 {
409 return GNUNET_SYSERR;
410 }
411
412 GNUNET_free (binary);
413 GNUNET_free (config);
414
415 done_reading = GNUNET_YES;
416 config = GNUNET_CONFIGURATION_serialize (cfg, &config_size);
417 GNUNET_CONFIGURATION_destroy (cfg);
418 cfg = NULL;
419 xconfig_size =
420 GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig);
421 GNUNET_free (config);
422 wc = GNUNET_new (struct WriteContext);
423 wc->length = xconfig_size + sizeof(struct GNUNET_TESTBED_HelperReply);
424 reply = GNUNET_realloc (xconfig, wc->length);
425 memmove (&reply[1], reply, xconfig_size);
426 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_REPLY);
427 reply->header.size = htons ((uint16_t) wc->length);
428 reply->config_size = htons ((uint16_t) config_size);
429 wc->data = reply;
430 write_task_id = GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
431 stdout_fd,
432 &write_task,
433 wc);
434 child_death_task_id = GNUNET_SCHEDULER_add_read_file (
435 GNUNET_TIME_UNIT_FOREVER_REL,
436 GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ),
437 &child_death_task,
438 NULL);
439 return GNUNET_OK;
440
441 error:
442 status = GNUNET_SYSERR;
443 GNUNET_SCHEDULER_shutdown ();
444 return GNUNET_SYSERR;
445}
446
447
448/**
449 * Task to read from stdin
450 *
451 * @param cls NULL
452 */
453static void
454read_task (void *cls)
455{
456 char buf[GNUNET_MAX_MESSAGE_SIZE];
457 ssize_t sread;
458
459 read_task_id = NULL;
460 sread = GNUNET_DISK_file_read (stdin_fd, buf, sizeof(buf));
461 if ((GNUNET_SYSERR == sread) || (0 == sread))
462 {
463 LOG_DEBUG ("STDIN closed\n");
464 GNUNET_SCHEDULER_shutdown ();
465 return;
466 }
467 if (GNUNET_YES == done_reading)
468 {
469 /* didn't expect any more data! */
470 GNUNET_break_op (0);
471 GNUNET_SCHEDULER_shutdown ();
472 return;
473 }
474 LOG_DEBUG ("Read %u bytes\n", (unsigned int) sread);
475 /* FIXME: could introduce a GNUNET_MST_read2 to read
476 directly from 'stdin_fd' and save a memcpy() here */
477 if (GNUNET_OK !=
478 GNUNET_MST_from_buffer (tokenizer, buf, sread, GNUNET_NO, GNUNET_NO))
479 {
480 GNUNET_break (0);
481 GNUNET_SCHEDULER_shutdown ();
482 return;
483 }
484 read_task_id /* No timeout while reading */
485 = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
486 stdin_fd,
487 &read_task,
488 NULL);
489}
490
491
492/**
493 * Main function that will be run.
494 *
495 * @param cls closure
496 * @param args remaining command-line arguments
497 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
498 * @param cfg configuration
499 */
500static void
501run (void *cls,
502 char *const *args,
503 const char *cfgfile,
504 const struct GNUNET_CONFIGURATION_Handle *cfg)
505{
506 LOG_DEBUG ("Starting interpreter loop helper...\n");
507 tokenizer = GNUNET_MST_create (&tokenizer_cb, NULL);
508 stdin_fd = GNUNET_DISK_get_handle_from_native (stdin);
509 stdout_fd = GNUNET_DISK_get_handle_from_native (stdout);
510 read_task_id = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
511 stdin_fd,
512 &read_task,
513 NULL);
514 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
515}
516
517
518/**
519 * Signal handler called for SIGCHLD.
520 */
521static void
522sighandler_child_death ()
523{
524 static char c;
525 int old_errno; /* back-up errno */
526
527 old_errno = errno;
528 GNUNET_break (
529 1 ==
530 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (sigpipe,
531 GNUNET_DISK_PIPE_END_WRITE),
532 &c,
533 sizeof(c)));
534 errno = old_errno;
535}
536
537
538/**
539 * Main function
540 *
541 * @param argc the number of command line arguments
542 * @param argv command line arg array
543 * @return return code
544 */
545int
546main (int argc, char **argv)
547{
548 struct GNUNET_SIGNAL_Context *shc_chld;
549 struct GNUNET_GETOPT_CommandLineOption options[] =
550 { GNUNET_GETOPT_OPTION_END };
551 int ret;
552
553 GNUNET_log_setup ("gnunet-helper-cmds",
554 "DEBUG",
555 NULL);
556 status = GNUNET_OK;
557 if (NULL ==
558 (sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE)))
559 {
560 GNUNET_break (0);
561 return 1;
562 }
563 shc_chld =
564 GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
565 ret = GNUNET_PROGRAM_run (argc,
566 argv,
567 "gnunet-helper-cmds",
568 "Helper for starting a local interpreter loop",
569 options,
570 &run,
571 NULL);
572 GNUNET_SIGNAL_handler_uninstall (shc_chld);
573 shc_chld = NULL;
574 GNUNET_DISK_pipe_close (sigpipe);
575 if (GNUNET_OK != ret)
576 return 1;
577 return (GNUNET_OK == status) ? 0 : 1;
578}
579
580
581/* end of gnunet-helper-testbed.c */
diff --git a/src/testbed/plugin_testcmd.c b/src/testbed/plugin_testcmd.c
new file mode 100644
index 000000000..90e4a90a1
--- /dev/null
+++ b/src/testbed/plugin_testcmd.c
@@ -0,0 +1,87 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2013, 2014 GNUnet e.V.
4
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.
9
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.
14
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/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/plugin_testcmd.c
23 * @brief a plugin to provide the API for running test cases.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_testing_ng_lib.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_testing_plugin.h"
30
31
32
33
34
35static void
36start_testcase ()
37{
38 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
39
40 struct GNUNET_TESTING_Command commands[] = {
41 GNUNET_TESTING_cmd_hello_world_birth ("hello-world-birth-0",
42 &now),
43 GNUNET_TESTING_cmd_hello_world ("hello-world-0","hello-world-birth-0",""),
44 GNUNET_TESTING_cmd_end ()
45 };
46
47 GNUNET_TESTING_run (NULL,
48 commands,
49 GNUNET_TIME_UNIT_FOREVER_REL);
50
51}
52
53
54/**
55 * Entry point for the plugin.
56 *
57 * @param cls NULL
58 * @return the exported block API
59 */
60void *
61libgnunet_plugin_testcmd_init (void *cls)
62{
63 struct GNUNET_TESTING_PluginFunctions *api;
64
65 api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions);
66 api->start_testcase = &start_testcase;
67 return api;
68}
69
70
71/**
72 * Exit point from the plugin.
73 *
74 * @param cls the return value from #libgnunet_plugin_block_test_init
75 * @return NULL
76 */
77void *
78libgnunet_plugin_testcmd_done (void *cls)
79{
80 struct GNUNET_TESTING_PluginFunctions *api = cls;
81
82 GNUNET_free (api);
83 return NULL;
84}
85
86
87/* end of plugin_gnsrecord_dns.c */
diff --git a/src/testbed/testbed_api.h b/src/testbed/testbed_api.h
index d4ef832ad..ea78a14ff 100644
--- a/src/testbed/testbed_api.h
+++ b/src/testbed/testbed_api.h
@@ -37,6 +37,11 @@
37 */ 37 */
38#define HELPER_TESTBED_BINARY "gnunet-helper-testbed" 38#define HELPER_TESTBED_BINARY "gnunet-helper-testbed"
39 39
40/**
41 * Cmds Helper binary name
42 */
43#define HELPER_CMDS_BINARY "gnunet-helper-cmds"
44
40 45
41/** 46/**
42 * Enumeration of operations 47 * Enumeration of operations
diff --git a/src/testbed/testbed_api_cmd_netjail_start_testbed.c b/src/testbed/testbed_api_cmd_netjail_start_testbed.c
index 786084917..dc8196e94 100644
--- a/src/testbed/testbed_api_cmd_netjail_start_testbed.c
+++ b/src/testbed/testbed_api_cmd_netjail_start_testbed.c
@@ -248,7 +248,7 @@ start_testbed (struct NetJailState *ns, struct
248 m_char, 248 m_char,
249 n_char, 249 n_char,
250 GNUNET_OS_get_libexec_binary_path ( 250 GNUNET_OS_get_libexec_binary_path (
251 HELPER_TESTBED_BINARY), 251 HELPER_CMDS_BINARY),
252 NULL}; 252 NULL};
253 unsigned int m = atoi (m_char); 253 unsigned int m = atoi (m_char);
254 unsigned int n = atoi (n_char); 254 unsigned int n = atoi (n_char);
@@ -285,9 +285,8 @@ start_testbed (struct NetJailState *ns, struct
285 GNUNET_YES, 285 GNUNET_YES,
286 NETJAIL_EXEC_SCRIPT, 286 NETJAIL_EXEC_SCRIPT,
287 script_argv, 287 script_argv,
288 & 288 &helper_mst,
289 helper_mst, 289 &exp_cb,
290 exp_cb,
291 tbc)); 290 tbc));
292 291
293 struct GNUNET_HELPER_Handle *helper = ns->helper[tbc->count - 1]; 292 struct GNUNET_HELPER_Handle *helper = ns->helper[tbc->count - 1];
diff --git a/src/testing/testing_api_loop.c b/src/testing/testing_api_loop.c
index 82f6d0cab..49ed48063 100644
--- a/src/testing/testing_api_loop.c
+++ b/src/testing/testing_api_loop.c
@@ -204,6 +204,8 @@ run_finish_task_next (void *cls)
204 } 204 }
205 else 205 else
206 { 206 {
207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
208 "Next task finished with an error.\n");
207 GNUNET_TESTING_interpreter_fail (); 209 GNUNET_TESTING_interpreter_fail ();
208 } 210 }
209 211
@@ -246,6 +248,8 @@ run_finish_task_sync (void *cls)
246 } 248 }
247 else 249 else
248 { 250 {
251 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
252 "Sync task finished with an error.\n");
249 GNUNET_TESTING_interpreter_fail (); 253 GNUNET_TESTING_interpreter_fail ();
250 } 254 }
251} 255}
@@ -325,16 +329,39 @@ GNUNET_TESTING_interpreter_fail ()
325{ 329{
326 struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip]; 330 struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
327 331
328 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 332 if (GNUNET_SYSERR == is->result)
329 "Failed at command `%s'\n", 333 return; /* ignore, we already failed! */
330 cmd->label); 334
331 while (GNUNET_TESTING_cmd_is_batch (cmd)) 335 if (NULL != cmd)
336 {
337 while (GNUNET_TESTING_cmd_is_batch (cmd))
338 {
339 cmd = GNUNET_TESTING_cmd_batch_get_current (cmd);
340 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
341 "Batch is at command `%s'\n",
342 cmd->label);
343 }
344
345 }
346 else
332 { 347 {
333 cmd = GNUNET_TESTING_cmd_batch_get_current (cmd);
334 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 348 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
335 "Batch is at command `%s'\n", 349 "cmd is NULL.\n");
350 }
351
352 if (NULL == cmd->label)
353 {
354 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
355 "Failed at command `%s'\n",
336 cmd->label); 356 cmd->label);
357
337 } 358 }
359 else
360 {
361 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
362 "cmd->label is NULL.\n");
363 }
364
338 is->result = GNUNET_SYSERR; 365 is->result = GNUNET_SYSERR;
339 GNUNET_SCHEDULER_shutdown (); 366 GNUNET_SCHEDULER_shutdown ();
340} 367}
@@ -386,7 +413,8 @@ interpreter_run (void *cls)
386 { 413 {
387 414
388 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 415 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
389 "Running command END\n"); 416 "Running command END %p\n",
417 is);
390 is->result = GNUNET_OK; 418 is->result = GNUNET_OK;
391 GNUNET_SCHEDULER_shutdown (); 419 GNUNET_SCHEDULER_shutdown ();
392 return; 420 return;
@@ -394,8 +422,9 @@ interpreter_run (void *cls)
394 else if (NULL != cmd) 422 else if (NULL != cmd)
395 { 423 {
396 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 424 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
397 "Running command `%s'\n", 425 "Running command `%s' %p\n",
398 cmd->label); 426 cmd->label,
427 is);
399 } 428 }
400 cmd->start_time 429 cmd->start_time
401 = cmd->last_req_time 430 = cmd->last_req_time