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