aboutsummaryrefslogtreecommitdiff
path: root/src/testing/gnunet-cmds-helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/testing/gnunet-cmds-helper.c')
-rw-r--r--src/testing/gnunet-cmds-helper.c570
1 files changed, 0 insertions, 570 deletions
diff --git a/src/testing/gnunet-cmds-helper.c b/src/testing/gnunet-cmds-helper.c
deleted file mode 100644
index 8f9e77709..000000000
--- a/src/testing/gnunet-cmds-helper.c
+++ /dev/null
@@ -1,570 +0,0 @@
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 * @file testbed/gnunet-cmds-helper.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_testing_ng_lib.h"
43#include "testing_cmds.h"
44#include "gnunet_testing_plugin.h"
45#include <zlib.h>
46
47
48/**
49 * Generic logging shortcut
50testing_api_cmd_block_until_all_peers_started.c */
51#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
52
53/**
54 * Debug logging shorthand
55 */
56#define LOG_DEBUG(...) LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
57
58#define NODE_BASE_IP "192.168.15."
59
60#define ROUTER_BASE_IP "92.68.150."
61
62/**
63 * Handle for a plugin.
64 */
65struct Plugin
66{
67 /**
68 * Name of the shared library.
69 */
70 char *library_name;
71
72 /**
73 * Plugin API.
74 */
75 struct GNUNET_TESTING_PluginFunctions *api;
76
77 /**
78 * IP address of the specific node the helper is running for.
79 *
80 */
81 char *node_ip;
82
83 /**
84 * Name of the test case plugin.
85 *
86 */
87 char *plugin_name;
88
89 /**
90 * The number of namespaces
91 *
92 */
93 char *global_n;
94
95 /**
96 * The number of local nodes per namespace.
97 *
98 */
99 char *local_m;
100
101 /**
102 * The number of the namespace this node is in.
103 *
104 */
105 char *n;
106
107 /**
108 * The number of the node in the namespace.
109 *
110 */
111 char *m;
112};
113
114/**
115 * Struct with information about a specific node and the whole network namespace setup.
116 *
117 */
118struct NodeIdentifier
119{
120 /**
121 * The number of the namespace this node is in.
122 *
123 */
124 char *n;
125
126 /**
127 * The number of the node in the namespace.
128 *
129 */
130 char *m;
131
132 /**
133 * The number of namespaces
134 *
135 */
136 char *global_n;
137
138 /**
139 * The number of local nodes per namespace.
140 *
141 */
142 char *local_m;
143};
144
145/**
146 * Context for a single write on a chunk of memory
147 */
148struct WriteContext
149{
150 /**
151 * The data to write
152 */
153 void *data;
154
155 /**
156 * The length of the data
157 */
158 size_t length;
159
160 /**
161 * The current position from where the write operation should begin
162 */
163 size_t pos;
164};
165
166/**
167 * The process handle to the testbed service
168
169static struct GNUNET_OS_Process *cmd_binary_process;*/
170
171/**
172 * Plugin to dynamically load a test case.
173 */
174struct Plugin *plugin;
175
176/**
177 * Handle to the testing system
178 */
179static struct GNUNET_TESTING_System *test_system;
180
181/**
182 * Our message stream tokenizer
183 */
184struct GNUNET_MessageStreamTokenizer *tokenizer;
185
186/**
187 * Disk handle from stdin
188 */
189static struct GNUNET_DISK_FileHandle *stdin_fd;
190
191/**
192 * Disk handle for stdout
193 */
194static struct GNUNET_DISK_FileHandle *stdout_fd;
195
196/**
197 * Pipe used to communicate shutdown via signal.
198 */
199static struct GNUNET_DISK_PipeHandle *sigpipe;
200
201/**
202 * Task identifier for the read task
203 */
204static struct GNUNET_SCHEDULER_Task *read_task_id;
205
206/**
207 * Task identifier for the write task
208 */
209static struct GNUNET_SCHEDULER_Task *write_task_id;
210
211/**
212 * Are we done reading messages from stdin?
213 */
214static int done_reading;
215
216/**
217 * Result to return in case we fail
218 */
219static int status;
220
221
222/**
223 * Task to shut down cleanly
224 *
225 * @param cls NULL
226 */
227static void
228shutdown_task (void *cls)
229{
230
231 LOG_DEBUG ("Shutting down.\n");
232
233 if (NULL != read_task_id)
234 {
235 GNUNET_SCHEDULER_cancel (read_task_id);
236 read_task_id = NULL;
237 }
238 if (NULL != write_task_id)
239 {
240 struct WriteContext *wc;
241
242 wc = GNUNET_SCHEDULER_cancel (write_task_id);
243 write_task_id = NULL;
244 GNUNET_free (wc->data);
245 GNUNET_free (wc);
246 }
247 if (NULL != stdin_fd)
248 (void) GNUNET_DISK_file_close (stdin_fd);
249 if (NULL != stdout_fd)
250 (void) GNUNET_DISK_file_close (stdout_fd);
251 GNUNET_MST_destroy (tokenizer);
252 tokenizer = NULL;
253
254 if (NULL != test_system)
255 {
256 GNUNET_TESTING_system_destroy (test_system, GNUNET_YES);
257 test_system = NULL;
258 }
259}
260
261
262/**
263 * Task to write to the standard out
264 *
265 * @param cls the WriteContext
266 */
267static void
268write_task (void *cls)
269{
270 struct WriteContext *wc = cls;
271 ssize_t bytes_wrote;
272
273 GNUNET_assert (NULL != wc);
274 write_task_id = NULL;
275 bytes_wrote = GNUNET_DISK_file_write (stdout_fd,
276 wc->data + wc->pos,
277 wc->length - wc->pos);
278 if (GNUNET_SYSERR == bytes_wrote)
279 {
280 LOG (GNUNET_ERROR_TYPE_WARNING,
281 "Cannot reply back successful initialization\n");
282 GNUNET_free (wc->data);
283 GNUNET_free (wc);
284 return;
285 }
286 wc->pos += bytes_wrote;
287 if (wc->pos == wc->length)
288 {
289 GNUNET_free (wc->data);
290 GNUNET_free (wc);
291 return;
292 }
293 write_task_id = GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
294 stdout_fd,
295 &write_task,
296 wc);
297}
298
299
300/**
301 * Callback to write a message to the master loop.
302 *
303 */
304static void
305write_message (struct GNUNET_MessageHeader *message, size_t msg_length)
306{
307 struct WriteContext *wc;
308
309 wc = GNUNET_new (struct WriteContext);
310 wc->length = msg_length;
311 wc->data = message;
312 write_task_id = GNUNET_SCHEDULER_add_write_file (
313 GNUNET_TIME_UNIT_FOREVER_REL,
314 stdout_fd,
315 &write_task,
316 wc);
317}
318
319
320/**
321 * Functions with this signature are called whenever a
322 * complete message is received by the tokenizer.
323 *
324 * Do not call #GNUNET_mst_destroy() in this callback
325 *
326 * @param cls identification of the client
327 * @param message the actual message
328 * @return #GNUNET_OK on success,
329 * #GNUNET_NO to stop further processing (no error)
330 * #GNUNET_SYSERR to stop further processing with error
331 */
332static int
333tokenizer_cb (void *cls, const struct GNUNET_MessageHeader *message)
334{
335
336 struct NodeIdentifier *ni = cls;
337 const struct GNUNET_CMDS_HelperInit *msg;
338 struct GNUNET_CMDS_HelperReply *reply;
339 char *binary;
340 char *plugin_name;
341 size_t plugin_name_size;
342 uint16_t msize;
343 size_t msg_length;
344 char *router_ip;
345 char *node_ip;
346
347 msize = ntohs (message->size);
348 if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_INIT == ntohs (message->type))
349 {
350 msg = (const struct GNUNET_CMDS_HelperInit *) message;
351 plugin_name_size = ntohs (msg->plugin_name_size);
352 if ((sizeof(struct GNUNET_CMDS_HelperInit) + plugin_name_size) > msize)
353 {
354 GNUNET_break (0);
355 LOG (GNUNET_ERROR_TYPE_WARNING,
356 "Received unexpected message -- exiting\n");
357 goto error;
358 }
359 plugin_name = GNUNET_malloc (plugin_name_size + 1);
360 GNUNET_strlcpy (plugin_name,
361 ((char *) &msg[1]),
362 plugin_name_size + 1);
363
364 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-cmd");
365
366 plugin = GNUNET_new (struct Plugin);
367 plugin->api = GNUNET_PLUGIN_load (plugin_name,
368 NULL);
369 plugin->library_name = GNUNET_strdup (basename (plugin_name));
370
371 plugin->global_n = ni->global_n;
372 plugin->local_m = ni->local_m;
373 plugin->n = ni->n;
374 plugin->m = ni->m;
375
376 router_ip = GNUNET_malloc (strlen (ROUTER_BASE_IP) + strlen (plugin->n)
377 + 1);
378 strcpy (router_ip, ROUTER_BASE_IP);
379 strcat (router_ip, plugin->n);
380
381 node_ip = GNUNET_malloc (strlen (NODE_BASE_IP) + strlen (plugin->m) + 1);
382 strcat (node_ip, NODE_BASE_IP);
383 strcat (node_ip, plugin->m);
384
385 plugin->api->start_testcase (&write_message, router_ip, node_ip, plugin->m,
386 plugin->n, plugin->local_m);
387
388 GNUNET_free (binary);
389
390 msg_length = sizeof(struct GNUNET_CMDS_HelperReply);
391 reply = GNUNET_new (struct GNUNET_CMDS_HelperReply);
392 reply->header.type = htons (GNUNET_MESSAGE_TYPE_CMDS_HELPER_REPLY);
393 reply->header.size = htons ((uint16_t) msg_length);
394
395 write_message ((struct GNUNET_MessageHeader *) reply, msg_length);
396
397 return GNUNET_OK;
398 }
399 else if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_ALL_PEERS_STARTED == ntohs (
400 message->type))
401 {
402 plugin->api->all_peers_started ();
403 return GNUNET_OK;
404 }
405 else
406 {
407 LOG (GNUNET_ERROR_TYPE_WARNING, "Received unexpected message -- exiting\n");
408 goto error;
409 }
410
411
412 error:
413 status = GNUNET_SYSERR;
414 LOG (GNUNET_ERROR_TYPE_ERROR,
415 "tokenizer shutting down!\n");
416 GNUNET_SCHEDULER_shutdown ();
417 return GNUNET_SYSERR;
418}
419
420
421/**
422 * Task to read from stdin
423 *
424 * @param cls NULL
425 */
426static void
427read_task (void *cls)
428{
429 char buf[GNUNET_MAX_MESSAGE_SIZE];
430 ssize_t sread;
431
432 read_task_id = NULL;
433 sread = GNUNET_DISK_file_read (stdin_fd, buf, sizeof(buf));
434 if ((GNUNET_SYSERR == sread) || (0 == sread))
435 {
436 LOG_DEBUG ("STDIN closed\n");
437 GNUNET_SCHEDULER_shutdown ();
438 return;
439 }
440 if (GNUNET_YES == done_reading)
441 {
442 /* didn't expect any more data! */
443 GNUNET_break_op (0);
444 LOG (GNUNET_ERROR_TYPE_ERROR,
445 "tokenizer shutting down during reading, didn't expect any more data!\n");
446 GNUNET_SCHEDULER_shutdown ();
447 return;
448 }
449 LOG_DEBUG ("Read %u bytes\n", (unsigned int) sread);
450 /* FIXME: could introduce a GNUNET_MST_read2 to read
451 directly from 'stdin_fd' and save a memcpy() here */
452 if (GNUNET_OK !=
453 GNUNET_MST_from_buffer (tokenizer, buf, sread, GNUNET_NO, GNUNET_NO))
454 {
455 GNUNET_break (0);
456 LOG (GNUNET_ERROR_TYPE_ERROR,
457 "tokenizer shutting down during reading, writing to buffer failed!\n");
458 GNUNET_SCHEDULER_shutdown ();
459 return;
460 }
461 read_task_id /* No timeout while reading */
462 = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
463 stdin_fd,
464 &read_task,
465 NULL);
466}
467
468
469/**
470 * Main function that will be run.
471 *
472 * @param cls closure
473 * @param args remaining command-line arguments
474 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
475 * @param cfg configuration
476 */
477static void
478run (void *cls,
479 char *const *args,
480 const char *cfgfile,
481 const struct GNUNET_CONFIGURATION_Handle *cfg)
482{
483 struct NodeIdentifier *ni = cls;
484
485 LOG_DEBUG ("Starting interpreter loop helper...\n");
486
487 tokenizer = GNUNET_MST_create (&tokenizer_cb, ni);
488 stdin_fd = GNUNET_DISK_get_handle_from_native (stdin);
489 stdout_fd = GNUNET_DISK_get_handle_from_native (stdout);
490 read_task_id = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
491 stdin_fd,
492 &read_task,
493 NULL);
494 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
495}
496
497
498/**
499 * Signal handler called for SIGCHLD.
500 */
501static void
502sighandler_child_death ()
503{
504 static char c;
505 int old_errno; /* back-up errno */
506
507 old_errno = errno;
508 GNUNET_break (
509 1 ==
510 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (sigpipe,
511 GNUNET_DISK_PIPE_END_WRITE),
512 &c,
513 sizeof(c)));
514 errno = old_errno;
515}
516
517
518/**
519 * Main function
520 *
521 * @param argc the number of command line arguments
522 * @param argv command line arg array
523 * @return return code
524 */
525int
526main (int argc, char **argv)
527{
528 struct NodeIdentifier *ni;
529 struct GNUNET_SIGNAL_Context *shc_chld;
530 struct GNUNET_GETOPT_CommandLineOption options[] =
531 { GNUNET_GETOPT_OPTION_END };
532 int ret;
533
534 GNUNET_log_setup ("gnunet-cmds-helper",
535 "DEBUG",
536 NULL);
537 ni = GNUNET_new (struct NodeIdentifier);
538 ni->global_n = argv[1];
539 ni->local_m = argv[2];
540 ni->m = argv[3];
541 ni->n = argv[4];
542
543 status = GNUNET_OK;
544 if (NULL ==
545 (sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE)))
546 {
547 GNUNET_break (0);
548 return 1;
549 }
550 shc_chld =
551 GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
552 ret = GNUNET_PROGRAM_run (argc,
553 argv,
554 "gnunet-cmds-helper",
555 "Helper for starting a local interpreter loop",
556 options,
557 &run,
558 ni);
559
560 GNUNET_SIGNAL_handler_uninstall (shc_chld);
561 shc_chld = NULL;
562 GNUNET_DISK_pipe_close (sigpipe);
563 GNUNET_free (ni);
564 if (GNUNET_OK != ret)
565 return 1;
566 return (GNUNET_OK == status) ? 0 : 1;
567}
568
569
570/* end of gnunet-cmds-helper.c */