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.c662
1 files changed, 662 insertions, 0 deletions
diff --git a/src/testing/gnunet-cmds-helper.c b/src/testing/gnunet-cmds-helper.c
new file mode 100644
index 000000000..d9fcf3541
--- /dev/null
+++ b/src/testing/gnunet-cmds-helper.c
@@ -0,0 +1,662 @@
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-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
50 */
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 char *node_ip;
78
79 char *plugin_name;
80
81 char *global_n;
82
83 char *local_m;
84
85 char *n;
86
87 char *m;
88};
89
90struct NodeIdentifier
91{
92 char *n;
93
94 char *m;
95
96 char *global_n;
97
98 char *local_m;
99};
100
101/**
102 * Context for a single write on a chunk of memory
103 */
104struct WriteContext
105{
106 /**
107 * The data to write
108 */
109 void *data;
110
111 /**
112 * The length of the data
113 */
114 size_t length;
115
116 /**
117 * The current position from where the write operation should begin
118 */
119 size_t pos;
120};
121
122struct Plugin *plugin;
123
124/**
125 * The process handle to the testbed service
126
127static struct GNUNET_OS_Process *cmd_binary_process;*/
128
129/**
130 * Handle to the testing system
131 */
132static struct GNUNET_TESTING_System *test_system;
133
134/**
135 * Our message stream tokenizer
136 */
137struct GNUNET_MessageStreamTokenizer *tokenizer;
138
139/**
140 * Disk handle from stdin
141 */
142static struct GNUNET_DISK_FileHandle *stdin_fd;
143
144/**
145 * Disk handle for stdout
146 */
147static struct GNUNET_DISK_FileHandle *stdout_fd;
148
149/**
150 * Pipe used to communicate shutdown via signal.
151 */
152static struct GNUNET_DISK_PipeHandle *sigpipe;
153
154/**
155 * Task identifier for the read task
156 */
157static struct GNUNET_SCHEDULER_Task *read_task_id;
158
159/**
160 * Task identifier for the write task
161 */
162static struct GNUNET_SCHEDULER_Task *write_task_id;
163
164/**
165 * Task to kill the child
166 */
167static struct GNUNET_SCHEDULER_Task *child_death_task_id;
168
169/**
170 * Are we done reading messages from stdin?
171 */
172static int done_reading;
173
174/**
175 * Result to return in case we fail
176 */
177static int status;
178
179
180/**
181 * Task to shut down cleanly
182 *
183 * @param cls NULL
184 */
185static void
186shutdown_task (void *cls)
187{
188
189 LOG_DEBUG ("Shutting down.\n");
190 LOG (GNUNET_ERROR_TYPE_ERROR,
191 "Shutting down tokenizer!\n");
192
193 if (NULL != read_task_id)
194 {
195 GNUNET_SCHEDULER_cancel (read_task_id);
196 read_task_id = NULL;
197 }
198 if (NULL != write_task_id)
199 {
200 struct WriteContext *wc;
201
202 wc = GNUNET_SCHEDULER_cancel (write_task_id);
203 write_task_id = NULL;
204 GNUNET_free (wc->data);
205 GNUNET_free (wc);
206 }
207 if (NULL != child_death_task_id)
208 {
209 GNUNET_SCHEDULER_cancel (child_death_task_id);
210 child_death_task_id = NULL;
211 }
212 if (NULL != stdin_fd)
213 (void) GNUNET_DISK_file_close (stdin_fd);
214 if (NULL != stdout_fd)
215 (void) GNUNET_DISK_file_close (stdout_fd);
216 GNUNET_MST_destroy (tokenizer);
217 tokenizer = NULL;
218
219 if (NULL != test_system)
220 {
221 GNUNET_TESTING_system_destroy (test_system, GNUNET_YES);
222 test_system = NULL;
223 }
224}
225
226
227/**
228 * Task to write to the standard out
229 *
230 * @param cls the WriteContext
231 */
232static void
233write_task (void *cls)
234{
235 struct WriteContext *wc = cls;
236 ssize_t bytes_wrote;
237
238 LOG (GNUNET_ERROR_TYPE_ERROR,
239 "Writing data!\n");
240
241 GNUNET_assert (NULL != wc);
242 write_task_id = NULL;
243 bytes_wrote = GNUNET_DISK_file_write (stdout_fd,
244 wc->data + wc->pos,
245 wc->length - wc->pos);
246 if (GNUNET_SYSERR == bytes_wrote)
247 {
248 LOG (GNUNET_ERROR_TYPE_WARNING,
249 "Cannot reply back successful initialization\n");
250 GNUNET_free (wc->data);
251 GNUNET_free (wc);
252 return;
253 }
254 wc->pos += bytes_wrote;
255 if (wc->pos == wc->length)
256 {
257 GNUNET_free (wc->data);
258 GNUNET_free (wc);
259 LOG (GNUNET_ERROR_TYPE_ERROR,
260 "Written successfully!\n");
261 return;
262 }
263 LOG (GNUNET_ERROR_TYPE_ERROR,
264 "Written data!\n");
265 write_task_id = GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
266 stdout_fd,
267 &write_task,
268 wc);
269}
270
271
272/**
273 * Task triggered whenever we receive a SIGCHLD (child
274 * process died).
275 *
276 * @param cls closure, NULL if we need to self-restart
277 */
278/*static void
279child_death_task (void *cls)
280{
281 const struct GNUNET_DISK_FileHandle *pr;
282 char c[16];
283
284 pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
285 child_death_task_id = NULL;
286 // consume the signal
287 GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof(c)));
288 LOG_DEBUG ("Got SIGCHLD\n");
289
290 LOG_DEBUG ("Child hasn't died. Resuming to monitor its status\n");
291 child_death_task_id =
292 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
293 pr,
294 &child_death_task,
295 NULL);
296}*/
297
298
299static void
300write_message (struct GNUNET_MessageHeader *message, size_t msg_length)
301{
302 struct WriteContext *wc;
303
304 LOG (GNUNET_ERROR_TYPE_ERROR,
305 "enter write_message!\n");
306 wc = GNUNET_new (struct WriteContext);
307 wc->length = msg_length;
308 wc->data = message;
309 write_task_id = GNUNET_SCHEDULER_add_write_file (
310 GNUNET_TIME_UNIT_FOREVER_REL,
311 stdout_fd,
312 &write_task,
313 wc);
314 LOG (GNUNET_ERROR_TYPE_ERROR,
315 "leave write_message!\n");
316}
317
318
319/**
320 * Function to run the test cases.
321 *
322 * @param cls plugin to use.
323 *
324 */
325/*static void
326run_plugin (void *cls)
327{
328 struct Plugin *plugin = cls;
329 char *router_ip;
330 char *node_ip;
331
332 router_ip = GNUNET_malloc (strlen (ROUTER_BASE_IP) + strlen (plugin->m) + 1);
333 strcpy (router_ip, ROUTER_BASE_IP);
334 strcat (router_ip, plugin->m);
335
336 node_ip = GNUNET_malloc (strlen (NODE_BASE_IP) + strlen (plugin->n) + 1);
337 strcat (node_ip, NODE_BASE_IP);
338 strcat (node_ip, plugin->n);
339
340 plugin->api->start_testcase (&write_message, router_ip, node_ip);
341
342}*/
343
344
345/**
346 * Functions with this signature are called whenever a
347 * complete message is received by the tokenizer.
348 *
349 * Do not call #GNUNET_mst_destroy() in this callback
350 *
351 * @param cls identification of the client
352 * @param message the actual message
353 * @return #GNUNET_OK on success,
354 * #GNUNET_NO to stop further processing (no error)
355 * #GNUNET_SYSERR to stop further processing with error
356 */
357static int
358tokenizer_cb (void *cls, const struct GNUNET_MessageHeader *message)
359{
360 struct NodeIdentifier *ni = cls;
361 const struct GNUNET_CMDS_HelperInit *msg;
362 struct GNUNET_CMDS_HelperReply *reply;
363 char *binary;
364 char *plugin_name;
365 size_t plugin_name_size;
366 uint16_t msize;
367 size_t msg_length;
368 char *router_ip;
369 char *node_ip;
370
371 LOG (GNUNET_ERROR_TYPE_ERROR,
372 "tokenizer \n");
373
374 msize = ntohs (message->size);
375 if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_INIT == ntohs (message->type))
376 {
377 msg = (const struct GNUNET_CMDS_HelperInit *) message;
378 plugin_name_size = ntohs (msg->plugin_name_size);
379 if ((sizeof(struct GNUNET_CMDS_HelperInit) + plugin_name_size) > msize)
380 {
381 GNUNET_break (0);
382 LOG (GNUNET_ERROR_TYPE_WARNING,
383 "Received unexpected message -- exiting\n");
384 goto error;
385 }
386 plugin_name = GNUNET_malloc (plugin_name_size + 1);
387 GNUNET_strlcpy (plugin_name,
388 ((char *) &msg[1]),
389 plugin_name_size + 1);
390
391 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-cmd");
392
393 LOG (GNUNET_ERROR_TYPE_ERROR,
394 "plugin_name: %s \n",
395 plugin_name);
396
397 // cmd_binary_process = GNUNET_OS_start_process (
398 /*GNUNET_OS_INHERIT_STD_ERR verbose? ,
399 NULL,
400 NULL,
401 NULL,
402 binary,
403 plugin_name,
404 ni->global_n,
405 ni->local_m,
406 ni->n,
407 ni->m,
408 NULL);*/
409
410 plugin = GNUNET_new (struct Plugin);
411 plugin->api = GNUNET_PLUGIN_load (plugin_name,
412 NULL);
413 plugin->library_name = GNUNET_strdup (basename (plugin_name));
414
415 plugin->global_n = ni->global_n;
416 plugin->local_m = ni->local_m;
417 plugin->n = ni->n;
418 plugin->m = ni->m;
419
420 router_ip = GNUNET_malloc (strlen (ROUTER_BASE_IP) + strlen (plugin->m)
421 + 1);
422 strcpy (router_ip, ROUTER_BASE_IP);
423 strcat (router_ip, plugin->m);
424
425 node_ip = GNUNET_malloc (strlen (NODE_BASE_IP) + strlen (plugin->n) + 1);
426 strcat (node_ip, NODE_BASE_IP);
427 strcat (node_ip, plugin->n);
428
429 plugin->api->start_testcase (&write_message, router_ip, node_ip, plugin->m,
430 plugin->n, plugin->local_m);
431
432 LOG (GNUNET_ERROR_TYPE_ERROR,
433 "We got here!\n");
434
435 /*if (NULL == cmd_binary_process)
436 {
437 LOG (GNUNET_ERROR_TYPE_ERROR,
438 "Starting plugin failed!\n");
439 return GNUNET_SYSERR;
440 }*/
441
442 LOG (GNUNET_ERROR_TYPE_ERROR,
443 "We got here 2!\n");
444
445 LOG (GNUNET_ERROR_TYPE_ERROR,
446 "global_n: %s local_n: %s n: %s m: %s.\n",
447 ni->global_n,
448 ni->local_m,
449 ni->n,
450 ni->m);
451
452 LOG (GNUNET_ERROR_TYPE_ERROR,
453 "We got here 3!\n");
454
455 GNUNET_free (binary);
456
457 // done_reading = GNUNET_YES;
458
459 msg_length = sizeof(struct GNUNET_CMDS_HelperReply);
460 reply = GNUNET_new (struct GNUNET_CMDS_HelperReply);
461 reply->header.type = htons (GNUNET_MESSAGE_TYPE_CMDS_HELPER_REPLY);
462 reply->header.size = htons ((uint16_t) msg_length);
463
464 LOG (GNUNET_ERROR_TYPE_ERROR,
465 "We got here 4!\n");
466
467 write_message ((struct GNUNET_MessageHeader *) reply, msg_length);
468
469 LOG (GNUNET_ERROR_TYPE_ERROR,
470 "We got here 5!\n");
471
472 /*child_death_task_id = GNUNET_SCHEDULER_add_read_file (
473 GNUNET_TIME_UNIT_FOREVER_REL,
474 GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ),
475 &child_death_task,
476 NULL);*/
477 return GNUNET_OK;
478 }
479 else if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_ALL_PEERS_STARTED == ntohs (
480 message->type))
481 {
482 plugin->api->all_peers_started ();
483 return GNUNET_OK;
484 }
485 else
486 {
487 LOG (GNUNET_ERROR_TYPE_WARNING, "Received unexpected message -- exiting\n");
488 goto error;
489 }
490
491
492 error:
493 status = GNUNET_SYSERR;
494 LOG (GNUNET_ERROR_TYPE_ERROR,
495 "tokenizer shutting down!\n");
496 GNUNET_SCHEDULER_shutdown ();
497 return GNUNET_SYSERR;
498}
499
500
501/**
502 * Task to read from stdin
503 *
504 * @param cls NULL
505 */
506static void
507read_task (void *cls)
508{
509 char buf[GNUNET_MAX_MESSAGE_SIZE];
510 ssize_t sread;
511
512 read_task_id = NULL;
513 sread = GNUNET_DISK_file_read (stdin_fd, buf, sizeof(buf));
514 if ((GNUNET_SYSERR == sread) || (0 == sread))
515 {
516 LOG_DEBUG ("STDIN closed\n");
517 LOG (GNUNET_ERROR_TYPE_ERROR,
518 "tokenizer shutting down during reading!\n");
519 GNUNET_SCHEDULER_shutdown ();
520 return;
521 }
522 if (GNUNET_YES == done_reading)
523 {
524 /* didn't expect any more data! */
525 GNUNET_break_op (0);
526 LOG (GNUNET_ERROR_TYPE_ERROR,
527 "tokenizer shutting down during reading, didn't expect any more data!\n");
528 GNUNET_SCHEDULER_shutdown ();
529 return;
530 }
531 LOG_DEBUG ("Read %u bytes\n", (unsigned int) sread);
532 LOG (GNUNET_ERROR_TYPE_ERROR,
533 "Read %u bytes\n", (unsigned int) sread);
534 /* FIXME: could introduce a GNUNET_MST_read2 to read
535 directly from 'stdin_fd' and save a memcpy() here */
536 if (GNUNET_OK !=
537 GNUNET_MST_from_buffer (tokenizer, buf, sread, GNUNET_NO, GNUNET_NO))
538 {
539 GNUNET_break (0);
540 LOG (GNUNET_ERROR_TYPE_ERROR,
541 "tokenizer shutting down during reading, writing to buffer failed!\n");
542 GNUNET_SCHEDULER_shutdown ();
543 return;
544 }
545 read_task_id /* No timeout while reading */
546 = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
547 stdin_fd,
548 &read_task,
549 NULL);
550}
551
552
553/**
554 * Main function that will be run.
555 *
556 * @param cls closure
557 * @param args remaining command-line arguments
558 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
559 * @param cfg configuration
560 */
561static void
562run (void *cls,
563 char *const *args,
564 const char *cfgfile,
565 const struct GNUNET_CONFIGURATION_Handle *cfg)
566{
567 struct NodeIdentifier *ni = cls;
568
569 LOG_DEBUG ("Starting interpreter loop helper...\n");
570
571 tokenizer = GNUNET_MST_create (&tokenizer_cb, ni);
572 stdin_fd = GNUNET_DISK_get_handle_from_native (stdin);
573 stdout_fd = GNUNET_DISK_get_handle_from_native (stdout);
574 read_task_id = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
575 stdin_fd,
576 &read_task,
577 NULL);
578 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
579}
580
581
582/**
583 * Signal handler called for SIGCHLD.
584 */
585static void
586sighandler_child_death ()
587{
588 static char c;
589 int old_errno; /* back-up errno */
590
591 old_errno = errno;
592 GNUNET_break (
593 1 ==
594 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (sigpipe,
595 GNUNET_DISK_PIPE_END_WRITE),
596 &c,
597 sizeof(c)));
598 errno = old_errno;
599}
600
601
602/**
603 * Main function
604 *
605 * @param argc the number of command line arguments
606 * @param argv command line arg array
607 * @return return code
608 */
609int
610main (int argc, char **argv)
611{
612 struct NodeIdentifier *ni;
613 struct GNUNET_SIGNAL_Context *shc_chld;
614 struct GNUNET_GETOPT_CommandLineOption options[] =
615 { GNUNET_GETOPT_OPTION_END };
616 int ret;
617
618 GNUNET_log_setup ("gnunet-cmds-helper",
619 "DEBUG",
620 NULL);
621 ni = GNUNET_new (struct NodeIdentifier);
622 ni->global_n = argv[1];
623 ni->local_m = argv[2];
624 ni->n = argv[3];
625 ni->m = argv[4];
626
627 LOG (GNUNET_ERROR_TYPE_ERROR,
628 "global_n: %s local_n: %s n: %s m: %s.\n",
629 ni->global_n,
630 ni->local_m,
631 ni->n,
632 ni->m);
633
634 status = GNUNET_OK;
635 if (NULL ==
636 (sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE)))
637 {
638 GNUNET_break (0);
639 return 1;
640 }
641 shc_chld =
642 GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
643 ret = GNUNET_PROGRAM_run (argc,
644 argv,
645 "gnunet-cmds-helper",
646 "Helper for starting a local interpreter loop",
647 options,
648 &run,
649 ni);
650 LOG (GNUNET_ERROR_TYPE_ERROR,
651 "run finished\n");
652 GNUNET_SIGNAL_handler_uninstall (shc_chld);
653 shc_chld = NULL;
654 GNUNET_DISK_pipe_close (sigpipe);
655 GNUNET_free (ni);
656 if (GNUNET_OK != ret)
657 return 1;
658 return (GNUNET_OK == status) ? 0 : 1;
659}
660
661
662/* end of gnunet-cmds-helper.c */