aboutsummaryrefslogtreecommitdiff
path: root/src/testing/testing_api_cmd_netjail_start_testsystem_v2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/testing/testing_api_cmd_netjail_start_testsystem_v2.c')
-rw-r--r--src/testing/testing_api_cmd_netjail_start_testsystem_v2.c718
1 files changed, 718 insertions, 0 deletions
diff --git a/src/testing/testing_api_cmd_netjail_start_testsystem_v2.c b/src/testing/testing_api_cmd_netjail_start_testsystem_v2.c
new file mode 100644
index 000000000..64ce549a4
--- /dev/null
+++ b/src/testing/testing_api_cmd_netjail_start_testsystem_v2.c
@@ -0,0 +1,718 @@
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 testing/testing_api_cmd_hello_world.c
23 * @brief Command to start the netjail peers.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_testing_ng_lib.h"
28#include "testing_cmds.h"
29
30#define NETJAIL_EXEC_SCRIPT "./../testing/netjail_exec_v2.sh"
31
32/**
33 * Struct to store messages send/received by the helper into a DLL
34 *
35 */
36struct HelperMessage
37{
38
39 /**
40 * Kept in a DLL.
41 */
42 struct HelperMessage *next;
43
44 /**
45 * Kept in a DLL.
46 */
47 struct HelperMessage *prev;
48
49 /**
50 * Size of the original message.
51 */
52 uint16_t bytes_msg;
53
54 /* Followed by @e bytes_msg of msg.*/
55};
56
57
58/**
59 * Struct to store information handed over to callbacks.
60 *
61 */
62struct NetJailState
63{
64 /**
65 * The complete topology infomation.
66 */
67 struct GNUNET_TESTING_NetjailTopology *topology;
68
69 /**
70 * Pointer to the return value of the test.
71 *
72 */
73 unsigned int *rv;
74
75 /**
76 * Head of the DLL which stores messages received by the helper.
77 *
78 */
79 struct HelperMessage *hp_messages_head;
80
81 /**
82 * Tail of the DLL which stores messages received by the helper.
83 *
84 */
85 struct HelperMessage *hp_messages_tail;
86
87 /**
88 * Array with handles of helper processes.
89 */
90 struct GNUNET_HELPER_Handle **helper;
91
92 /**
93 * Size of the array NetJailState#helper.
94 *
95 */
96 unsigned int n_helper;
97
98 /**
99 * Number of nodes in a natted subnet.
100 *
101 */
102 unsigned int local_m;
103
104 /**
105 * Number of natted subnets.
106 *
107 */
108 unsigned int global_n;
109
110 /**
111 * Number of global known nodes.
112 *
113 */
114 unsigned int known;
115
116 /**
117 * The send handle for the helper
118 */
119 struct GNUNET_HELPER_SendHandle **shandle;
120
121 /**
122 * Size of the array NetJailState#shandle.
123 *
124 */
125 unsigned int n_shandle;
126
127 /**
128 * The messages send to the helper.
129 */
130 struct GNUNET_MessageHeader **msg;
131
132 /**
133 * Size of the array NetJailState#msg.
134 *
135 */
136 unsigned int n_msg;
137
138 /**
139 * Number of test environments started.
140 *
141 */
142 unsigned int number_of_testsystems_started;
143
144 /**
145 * Number of peers started.
146 *
147 */
148 unsigned int number_of_peers_started;
149
150 /**
151 * Number of local tests finished.
152 *
153 */
154 unsigned int number_of_local_test_finished;
155
156 /**
157 * Name of the test case plugin the helper will load.
158 *
159 */
160 char *plugin_name;
161
162 /**
163 * HEAD of the DLL containing TestingSystemCount.
164 *
165 */
166 struct TestingSystemCount *tbcs_head;
167
168 /**
169 * TAIL of the DLL containing TestingSystemCount.
170 *
171 */
172 struct TestingSystemCount *tbcs_tail;
173};
174
175/**
176 * Struct containing the number of the test environment and the NetJailState which
177 * will be handed to callbacks specific to a test environment.
178 */
179struct TestingSystemCount
180{
181 /**
182 * Kept in a DLL.
183 */
184 struct TestingSystemCount *next;
185
186 /**
187 * Kept in a DLL.
188 */
189 struct TestingSystemCount *prev;
190
191 /**
192 * The number of the test environment.
193 *
194 */
195 unsigned int count;
196
197 /**
198 * Struct to store information handed over to callbacks.
199 *
200 */
201 struct NetJailState *ns;
202};
203
204/**
205* Code to clean up resource this cmd used.
206*
207* @param cls closure
208* @param cmd current CMD being cleaned up.
209*/
210static void
211netjail_exec_cleanup (void *cls,
212 const struct GNUNET_TESTING_Command *cmd)
213{
214 struct NetJailState *ns = cls;
215 struct HelperMessage *message_pos;
216 struct TestingSystemCount *tbc_pos;
217
218 while (NULL != (message_pos = ns->hp_messages_head))
219 {
220 GNUNET_CONTAINER_DLL_remove (ns->hp_messages_head,
221 ns->hp_messages_tail,
222 message_pos);
223 GNUNET_free (message_pos);
224 }
225 while (NULL != (tbc_pos = ns->tbcs_head))
226 {
227 GNUNET_CONTAINER_DLL_remove (ns->tbcs_head,
228 ns->tbcs_tail,
229 tbc_pos);
230 GNUNET_free (tbc_pos);
231 }
232 GNUNET_free (ns);
233}
234
235
236/**
237 * This function prepares an array with traits.
238 *
239 */
240static int
241netjail_exec_traits (void *cls,
242 const void **ret,
243 const char *trait,
244 unsigned int index)
245{
246 struct NetJailState *ns = cls;
247 struct GNUNET_HELPER_Handle **helper = ns->helper;
248 struct HelperMessage *hp_messages_head = ns->hp_messages_head;
249
250
251 struct GNUNET_TESTING_Trait traits[] = {
252 {
253 .index = 0,
254 .trait_name = "helper_handles",
255 .ptr = (const void *) helper,
256 },
257 {
258 .index = 1,
259 .trait_name = "hp_msgs_head",
260 .ptr = (const void *) hp_messages_head,
261 },
262 GNUNET_TESTING_trait_end ()
263 };
264
265 return GNUNET_TESTING_get_trait (traits,
266 ret,
267 trait,
268 index);
269}
270
271
272/**
273 * Offer handles to testing cmd helper from trait
274 *
275 * @param cmd command to extract the message from.
276 * @param pt pointer to message.
277 * @return #GNUNET_OK on success.
278 */
279int
280GNUNET_TESTING_get_trait_helper_handles_v2 (const struct
281 GNUNET_TESTING_Command *cmd,
282 struct GNUNET_HELPER_Handle ***
283 helper)
284{
285 return cmd->traits (cmd->cls,
286 (const void **) helper,
287 "helper_handles",
288 (unsigned int) 0);
289}
290
291
292/**
293 * Continuation function from GNUNET_HELPER_send()
294 *
295 * @param cls closure
296 * @param result GNUNET_OK on success,
297 * GNUNET_NO if helper process died
298 * GNUNET_SYSERR during GNUNET_HELPER_stop
299 */
300static void
301clear_msg (void *cls, int result)
302{
303 struct TestingSystemCount *tbc = cls;
304 struct NetJailState *ns = tbc->ns;
305
306 GNUNET_assert (NULL != ns->shandle[tbc->count - 1]);
307 ns->shandle[tbc->count - 1] = NULL;
308 GNUNET_free (ns->msg[tbc->count - 1]);
309 ns->msg[tbc->count - 1] = NULL;
310}
311
312
313/**
314 * Functions with this signature are called whenever a
315 * complete message is received by the tokenizer.
316 *
317 * Do not call GNUNET_SERVER_mst_destroy in callback
318 *
319 * @param cls closure
320 * @param client identification of the client
321 * @param message the actual message
322 *
323 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
324 */
325static int
326helper_mst (void *cls, const struct GNUNET_MessageHeader *message)
327{
328 struct TestingSystemCount *tbc = cls;
329 struct NetJailState *ns = tbc->ns;
330 struct HelperMessage *hp_msg;
331
332 if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_REPLY == ntohs (message->type))
333 {
334 ns->number_of_testsystems_started++;
335 }
336 else if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_PEER_STARTED == ntohs (
337 message->type))
338 {
339 ns->number_of_peers_started++;
340 }
341 else if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_LOCAL_FINISHED == ntohs (
342 message->type))
343 {
344 ns->number_of_local_test_finished++;
345 }
346 else
347 {
348 hp_msg = GNUNET_new (struct HelperMessage);
349 hp_msg->bytes_msg = message->size;
350 memcpy (&hp_msg[1], message, message->size);
351 GNUNET_CONTAINER_DLL_insert (ns->hp_messages_head, ns->hp_messages_tail,
352 hp_msg);
353 }
354
355 return GNUNET_OK;
356}
357
358
359/**
360 * Callback called if there was an exception during execution of the helper.
361 *
362 */
363static void
364exp_cb (void *cls)
365{
366 struct NetJailState *ns = cls;
367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called exp_cb.\n");
368 *ns->rv = 1;
369}
370
371
372/**
373 * Function to initialize a init message for the helper.
374 *
375 * @param m_char The actual node in a namespace. //TODO Change this to unsigned int
376 * @param n_char The actual namespace. //TODO Change this to unsigned int
377 * @param plugin_name Name of the test case plugin the helper will load.
378 *
379 */
380static struct GNUNET_CMDS_HelperInit *
381create_helper_init_msg_ (const char *plugin_name)
382{
383 struct GNUNET_CMDS_HelperInit *msg;
384 uint16_t plugin_name_len;
385 uint16_t msg_size;
386
387 GNUNET_assert (NULL != plugin_name);
388 plugin_name_len = strlen (plugin_name);
389 msg_size = sizeof(struct GNUNET_CMDS_HelperInit) + plugin_name_len;
390 msg = GNUNET_malloc (msg_size);
391 msg->header.size = htons (msg_size);
392 msg->header.type = htons (GNUNET_MESSAGE_TYPE_CMDS_HELPER_INIT);
393 msg->plugin_name_size = htons (plugin_name_len);
394 GNUNET_memcpy ((char *) &msg[1],
395 plugin_name,
396 plugin_name_len);
397 return msg;
398}
399
400
401/**
402 * Function which start a single helper process.
403 *
404 */
405static void
406start_helper (struct NetJailState *ns, struct
407 GNUNET_CONFIGURATION_Handle *config,
408 unsigned int m,
409 unsigned int n)
410{
411 struct GNUNET_HELPER_Handle *helper;
412 struct GNUNET_CMDS_HelperInit *msg;
413 struct TestingSystemCount *tbc;
414 char *m_char, *n_char, *global_n_char, *local_m_char, *known_char, *node_id,
415 *plugin;
416 pid_t pid;
417 unsigned int script_num;
418 struct GNUNET_ShortHashCode *hkey;
419 struct GNUNET_HashCode hc;
420 struct GNUNET_TESTING_NetjailTopology *topology = ns->topology;
421 struct GNUNET_TESTING_NetjailNode *node;
422 struct GNUNET_TESTING_NetjailNamespace *namespace;
423
424
425 if (0 == m)
426 script_num = n - 1;
427 else
428 script_num = n - 1 + (n - 1) * ns->local_m + m + ns->known;
429 pid = getpid ();
430
431 GNUNET_asprintf (&m_char, "%u", m);
432 GNUNET_asprintf (&n_char, "%u", n);
433 GNUNET_asprintf (&local_m_char, "%u", ns->local_m);
434 GNUNET_asprintf (&global_n_char, "%u",ns->global_n);
435 GNUNET_asprintf (&known_char, "%u",ns->known);
436 GNUNET_asprintf (&node_id, "%06x-%08x\n",
437 pid,
438 script_num);
439
440
441 char *const script_argv[] = {NETJAIL_EXEC_SCRIPT,
442 m_char,
443 n_char,
444 GNUNET_OS_get_libexec_binary_path (
445 HELPER_CMDS_BINARY),
446 global_n_char,
447 local_m_char,
448 node_id,
449 NULL};
450
451 unsigned int helper_check = GNUNET_OS_check_helper_binary (
452 NETJAIL_EXEC_SCRIPT,
453 GNUNET_YES,
454 NULL);
455
456 tbc = GNUNET_new (struct TestingSystemCount);
457 tbc->ns = ns;
458 if (0 == m)
459 tbc->count = n;
460 else
461 tbc->count = (n - 1) * ns->local_m + m + ns->known;
462
463 GNUNET_CONTAINER_DLL_insert (ns->tbcs_head, ns->tbcs_tail,
464 tbc);
465
466
467 if (GNUNET_NO == helper_check)
468 {
469 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
470 "No SUID for %s!\n",
471 NETJAIL_EXEC_SCRIPT);
472 *ns->rv = 1;
473 }
474 else if (GNUNET_NO == helper_check)
475 {
476 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
477 "%s not found!\n",
478 NETJAIL_EXEC_SCRIPT);
479 *ns->rv = 1;
480 }
481
482 GNUNET_array_append (ns->helper, ns->n_helper, GNUNET_HELPER_start (
483 GNUNET_YES,
484 NETJAIL_EXEC_SCRIPT,
485 script_argv,
486 &helper_mst,
487 &exp_cb,
488 tbc));
489
490 helper = ns->helper[tbc->count - 1];
491
492 hkey = GNUNET_new (struct GNUNET_ShortHashCode);
493
494 plugin = ns->plugin_name;
495
496 if (0 == m)
497 {
498
499 GNUNET_CRYPTO_hash (&n, sizeof(n), &hc);
500 memcpy (hkey,
501 &hc,
502 sizeof (*hkey));
503 if (1 == GNUNET_CONTAINER_multishortmap_contains (topology->map_globals,
504 hkey))
505 {
506 node = GNUNET_CONTAINER_multishortmap_get (topology->map_globals,
507 hkey);
508 plugin = node->plugin;
509 }
510
511 }
512 else
513 {
514 GNUNET_CRYPTO_hash (&m, sizeof(m), &hc);
515 memcpy (hkey,
516 &hc,
517 sizeof (*hkey));
518 if (1 == GNUNET_CONTAINER_multishortmap_contains (topology->map_namespaces,
519 hkey))
520 {
521 namespace = GNUNET_CONTAINER_multishortmap_get (topology->map_namespaces,
522 hkey);
523 GNUNET_CRYPTO_hash (&n, sizeof(n), &hc);
524 memcpy (hkey,
525 &hc,
526 sizeof (*hkey));
527 if (1 == GNUNET_CONTAINER_multishortmap_contains (namespace->nodes,
528 hkey))
529 {
530 node = GNUNET_CONTAINER_multishortmap_get (namespace->nodes,
531 hkey);
532 plugin = node->plugin;
533 }
534 }
535
536
537 }
538
539 msg = create_helper_init_msg_ (plugin);
540
541 GNUNET_array_append (ns->msg, ns->n_msg, &msg->header);
542
543 GNUNET_array_append (ns->shandle, ns->n_shandle, GNUNET_HELPER_send (
544 helper,
545 &msg->header,
546 GNUNET_NO,
547 &clear_msg,
548 tbc));
549
550 if (NULL == ns->shandle[tbc->count - 1])
551 {
552 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
553 "Send handle is NULL!\n");
554 GNUNET_free (msg);
555 *ns->rv = 1;
556 }
557}
558
559
560/**
561* This function starts a helper process for each node.
562*
563* @param cls closure.
564* @param cmd CMD being run.
565* @param is interpreter state.
566*/
567static void
568netjail_exec_run (void *cls,
569 const struct GNUNET_TESTING_Command *cmd,
570 struct GNUNET_TESTING_Interpreter *is)
571{
572 struct NetJailState *ns = cls;
573 struct GNUNET_CONFIGURATION_Handle *config =
574 GNUNET_CONFIGURATION_create ();
575
576 for (int i = 1; i <= ns->known; i++)
577 {
578 start_helper (ns, config,
579 i,
580 0);
581 }
582
583 for (int i = 1; i <= ns->global_n; i++)
584 {
585 for (int j = 1; j <= ns->local_m; j++)
586 {
587 start_helper (ns, config,
588 j,
589 i);
590 }
591 }
592}
593
594
595static void
596send_all_peers_started (unsigned int i, unsigned int j, struct NetJailState *ns)
597{
598 unsigned int total_number = ns->local_m * ns->global_n + ns->known;
599 struct GNUNET_CMDS_ALL_PEERS_STARTED *reply;
600 size_t msg_length;
601 struct GNUNET_HELPER_Handle *helper;
602 struct TestingSystemCount *tbc;
603
604 tbc = GNUNET_new (struct TestingSystemCount);
605 tbc->ns = ns;
606 // TODO This needs to be more generic. As we send more messages back and forth, we can not grow the arrays again and again, because this is to error prone.
607 if (0 == i)
608 tbc->count = j + total_number;
609 else
610 tbc->count = (i - 1) * ns->local_m + j + total_number + ns->known;
611
612 helper = ns->helper[tbc->count - 1 - total_number];
613 msg_length = sizeof(struct GNUNET_CMDS_ALL_PEERS_STARTED);
614 reply = GNUNET_new (struct GNUNET_CMDS_ALL_PEERS_STARTED);
615 reply->header.type = htons (
616 GNUNET_MESSAGE_TYPE_CMDS_HELPER_ALL_PEERS_STARTED);
617 reply->header.size = htons ((uint16_t) msg_length);
618
619 GNUNET_array_append (ns->msg, ns->n_msg, &reply->header);
620
621 struct GNUNET_HELPER_SendHandle *sh = GNUNET_HELPER_send (
622 helper,
623 &reply->header,
624 GNUNET_NO,
625 &clear_msg,
626 tbc);
627
628 GNUNET_array_append (ns->shandle, ns->n_shandle, sh);
629}
630
631
632/**
633 * This function checks on three different information.
634 *
635 * 1. Did all helpers start. This is only logged.
636 * 2. Did all peer start.
637 * In this case a GNUNET_MESSAGE_TYPE_CMDS_HELPER_ALL_PEERS_STARTED is send to all peers.
638 * 3. Did all peers finished the test case. In this case interpreter_next will be called.
639 *
640 */
641static int
642netjail_start_finish (void *cls,
643 GNUNET_SCHEDULER_TaskCallback cont,
644 void *cont_cls)
645{
646 unsigned int ret = GNUNET_NO;
647 struct NetJailState *ns = cls;
648 unsigned int total_number = ns->local_m * ns->global_n + ns->known;
649
650
651 if (ns->number_of_local_test_finished == total_number)
652 {
653 ret = GNUNET_YES;
654 cont (cont_cls);
655 }
656
657 if (ns->number_of_testsystems_started == total_number)
658 {
659 ns->number_of_testsystems_started = 0;
660 }
661
662 if (ns->number_of_peers_started == total_number)
663 {
664 for (int i = 1; i <= ns->known; i++)
665 {
666 send_all_peers_started (0,i, ns);
667 }
668
669 for (int i = 1; i <= ns->global_n; i++)
670 {
671 for (int j = 1; j <= ns->local_m; j++)
672 {
673 send_all_peers_started (i,j, ns);
674 }
675 }
676 ns->number_of_peers_started = 0;
677 }
678 return ret;
679}
680
681
682/**
683 * Create command.
684 *
685 * @param label Name for the command.
686 * @param topology_config Configuration file for the test topology.
687 * @param rv Pointer to the return value of the test.
688 * @return command.
689 */
690struct GNUNET_TESTING_Command
691GNUNET_TESTING_cmd_netjail_start_testing_system_v2 (const char *label,
692 const char *topology_config,
693 unsigned int *rv)
694{
695 struct NetJailState *ns;
696
697 struct GNUNET_TESTING_NetjailTopology *topology =
698 GNUNET_TESTING_get_topo_from_file (topology_config);
699
700 ns = GNUNET_new (struct NetJailState);
701 ns->rv = rv;
702 ns->local_m = topology->nodes_m;
703 ns->global_n = topology->namespaces_n;
704 ns->known = topology->nodes_x;
705 ns->plugin_name = topology->plugin;
706 ns->topology = topology;
707
708 struct GNUNET_TESTING_Command cmd = {
709 .cls = ns,
710 .label = label,
711 .run = &netjail_exec_run,
712 .finish = &netjail_start_finish,
713 .cleanup = &netjail_exec_cleanup,
714 .traits = &netjail_exec_traits
715 };
716
717 return cmd;
718}