GNUnet  0.11.x
testing_api_cmd_netjail_start_testsystem.c
Go to the documentation of this file.
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 
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 
37 {
38 
43 
48 
52  uint16_t bytes_msg;
53 
54  /* Followed by @e bytes_msg of msg.*/
55 };
56 
57 
62 struct NetJailState
63 {
68  unsigned int *rv;
69 
75 
81 
86 
91  unsigned int n_helper;
92 
97  char *local_m;
98 
103  char *global_n;
104 
109 
114  unsigned int n_shandle;
115 
120 
125  unsigned int n_msg;
126 
132 
138 
144 
149  char *plugin_name;
150 
156 
162 };
163 
169 {
174 
179 
184  unsigned int count;
185 
190  struct NetJailState *ns;
191 };
192 
199 static void
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 
229 static int
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  },
252  };
253 
254  return GNUNET_TESTING_get_trait (traits,
255  ret,
256  trait,
257  index);
258 }
259 
260 
268 int
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 
288 static void
289 clear_msg (void *cls, int result)
290 {
291  struct TestingSystemCount *tbc = cls;
292  struct NetJailState *ns = tbc->ns;
293 
294  GNUNET_assert (NULL != ns->shandle[tbc->count - 1]);
295  ns->shandle[tbc->count - 1] = NULL;
296  GNUNET_free (ns->msg[tbc->count - 1]);
297  ns->msg[tbc->count - 1] = NULL;
298 }
299 
300 
313 static int
314 helper_mst (void *cls, const struct GNUNET_MessageHeader *message)
315 {
316  struct TestingSystemCount *tbc = cls;
317  struct NetJailState *ns = tbc->ns;
318  struct HelperMessage *hp_msg;
319 
320  if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_REPLY == ntohs (message->type))
321  {
322  ns->number_of_testsystems_started++;
323  }
325  message->type))
326  {
327  ns->number_of_peers_started++;
328  }
330  message->type))
331  {
332  ns->number_of_local_test_finished++;
333  }
334  else
335  {
336  hp_msg = GNUNET_new (struct HelperMessage);
337  hp_msg->bytes_msg = message->size;
338  memcpy (&hp_msg[1], message, message->size);
339  GNUNET_CONTAINER_DLL_insert (ns->hp_messages_head, ns->hp_messages_tail,
340  hp_msg);
341  }
342 
343  return GNUNET_OK;
344 }
345 
346 
351 static void
352 exp_cb (void *cls)
353 {
354  struct NetJailState *ns = cls;
355  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called exp_cb.\n");
356  *ns->rv = 1;
357 }
358 
359 
368 static struct GNUNET_CMDS_HelperInit *
370  char *n_char,
371  const char *plugin_name)
372 {
373  struct GNUNET_CMDS_HelperInit *msg;
374  uint16_t plugin_name_len;
375  uint16_t msg_size;
376 
377  GNUNET_assert (NULL != plugin_name);
378  plugin_name_len = strlen (plugin_name);
379  msg_size = sizeof(struct GNUNET_CMDS_HelperInit) + plugin_name_len;
380  msg = GNUNET_malloc (msg_size);
381  msg->header.size = htons (msg_size);
383  msg->plugin_name_size = htons (plugin_name_len);
384  GNUNET_memcpy ((char *) &msg[1],
385  plugin_name,
386  plugin_name_len);
387  return msg;
388 }
389 
390 
395 static void
396 start_helper (struct NetJailState *ns, struct
398  char *m_char,
399  char *n_char)
400 {
401  struct GNUNET_HELPER_Handle *helper;
402  struct GNUNET_CMDS_HelperInit *msg;
403  struct TestingSystemCount *tbc;
404  char *const script_argv[] = {NETJAIL_EXEC_SCRIPT,
405  m_char,
406  n_char,
409  ns->global_n,
410  ns->local_m,
411  NULL};
412  unsigned int m = atoi (m_char);
413  unsigned int n = atoi (n_char);
414  unsigned int helper_check = GNUNET_OS_check_helper_binary (
416  GNUNET_YES,
417  NULL);
418 
419  tbc = GNUNET_new (struct TestingSystemCount);
420  tbc->ns = ns;
421  tbc->count = (n - 1) * atoi (ns->local_m) + m;
422 
423  GNUNET_CONTAINER_DLL_insert (ns->tbcs_head, ns->tbcs_tail,
424  tbc);
425 
426 
427  if (GNUNET_NO == helper_check)
428  {
430  "No SUID for %s!\n",
432  *ns->rv = 1;
433  }
434  else if (GNUNET_NO == helper_check)
435  {
437  "%s not found!\n",
439  *ns->rv = 1;
440  }
441 
442  GNUNET_array_append (ns->helper, ns->n_helper, GNUNET_HELPER_start (
443  GNUNET_YES,
445  script_argv,
446  &helper_mst,
447  &exp_cb,
448  tbc));
449 
450  helper = ns->helper[tbc->count - 1];
451 
452  msg = create_helper_init_msg_ (m_char,
453  n_char,
454  ns->plugin_name);
455  GNUNET_array_append (ns->msg, ns->n_msg, &msg->header);
456 
457  GNUNET_array_append (ns->shandle, ns->n_shandle, GNUNET_HELPER_send (
458  helper,
459  &msg->header,
460  GNUNET_NO,
461  &clear_msg,
462  tbc));
463 
464  if (NULL == ns->shandle[tbc->count - 1])
465  {
467  "Send handle is NULL!\n");
468  GNUNET_free (msg);
469  *ns->rv = 1;
470  }
471 }
472 
473 
481 static void
482 netjail_exec_run (void *cls,
483  const struct GNUNET_TESTING_Command *cmd,
485 {
486  char str_m[12];
487  char str_n[12];
488  struct NetJailState *ns = cls;
491 
492  for (int i = 1; i <= atoi (ns->global_n); i++)
493  {
494  for (int j = 1; j <= atoi (ns->local_m); j++)
495  {
496  sprintf (str_n, "%d", i);
497  sprintf (str_m, "%d", j);
499  str_m,
500  str_n);
501  }
502  }
503 }
504 
505 
515 static int
518  void *cont_cls)
519 {
520  unsigned int ret = GNUNET_NO;
521  struct NetJailState *ns = cls;
522  unsigned int total_number = atoi (ns->local_m) * atoi (ns->global_n);
523  struct GNUNET_CMDS_ALL_PEERS_STARTED *reply;
524  size_t msg_length;
525  struct GNUNET_HELPER_Handle *helper;
526  struct TestingSystemCount *tbc;
527 
528  if (ns->number_of_local_test_finished == total_number)
529  {
530  ret = GNUNET_YES;
531  cont (cont_cls);
532  }
533 
534  if (ns->number_of_testsystems_started == total_number)
535  {
536  ns->number_of_testsystems_started = 0;
537  }
538 
539  if (ns->number_of_peers_started == total_number)
540  {
541  for (int i = 1; i <= atoi (ns->global_n); i++)
542  {
543  for (int j = 1; j <= atoi (ns->local_m); j++)
544  {
545  tbc = GNUNET_new (struct TestingSystemCount);
546  tbc->ns = ns;
547  // 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.
548  tbc->count = (i - 1) * atoi (ns->local_m) + j + total_number;
549 
550  helper = ns->helper[tbc->count - 1 - total_number];
551  msg_length = sizeof(struct GNUNET_CMDS_ALL_PEERS_STARTED);
552  reply = GNUNET_new (struct GNUNET_CMDS_ALL_PEERS_STARTED);
553  reply->header.type = htons (
555  reply->header.size = htons ((uint16_t) msg_length);
556 
557  GNUNET_array_append (ns->msg, ns->n_msg, &reply->header);
558 
560  helper,
561  &reply->header,
562  GNUNET_NO,
563  &clear_msg,
564  tbc);
565 
566  GNUNET_array_append (ns->shandle, ns->n_shandle, sh);
567  }
568  }
569  ns->number_of_peers_started = 0;
570  }
571  return ret;
572 }
573 
574 
587  char *local_m,
588  char *global_n,
589  char *plugin_name,
590  unsigned int *rv)
591 {
592  struct NetJailState *ns;
593 
594  ns = GNUNET_new (struct NetJailState);
595  ns->local_m = local_m;
596  ns->global_n = global_n;
597  ns->plugin_name = plugin_name;
598  ns->rv = rv;
599 
600  struct GNUNET_TESTING_Command cmd = {
601  .cls = ns,
602  .label = label,
603  .run = &netjail_exec_run,
604  .finish = &netjail_start_finish,
605  .cleanup = &netjail_exec_cleanup,
606  .traits = &netjail_exec_traits
607  };
608 
609  return cmd;
610 }
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static struct GNUNET_NAMESTORE_Handle * ns
Handle to the namestore.
Definition: gnunet-abd.c:41
static struct GNUNET_ARM_MonitorHandle * m
Monitor connection with ARM.
Definition: gnunet-arm.c:104
static struct SolverHandle * sh
static int result
Global testing status.
static char * plugin_name
Name of our plugin.
static const struct GNUNET_CONFIGURATION_Handle * config
#define GNUNET_log(kind,...)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
@ GNUNET_OK
Definition: gnunet_common.h:95
@ GNUNET_YES
Definition: gnunet_common.h:97
@ GNUNET_NO
Definition: gnunet_common.h:94
struct GNUNET_TESTING_Trait GNUNET_TESTING_trait_end(void)
"end" trait.
int GNUNET_TESTING_get_trait(const struct GNUNET_TESTING_Trait *traits, const void **ret, const char *trait, unsigned int index)
Extract a trait.
struct GNUNET_CONFIGURATION_Handle * GNUNET_CONFIGURATION_create(void)
Create a new configuration object.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
struct GNUNET_HELPER_SendHandle * GNUNET_HELPER_send(struct GNUNET_HELPER_Handle *h, const struct GNUNET_MessageHeader *msg, int can_drop, GNUNET_HELPER_Continuation cont, void *cont_cls)
Send an message to the helper.
Definition: helper.c:657
struct GNUNET_HELPER_Handle * GNUNET_HELPER_start(int with_control_pipe, const char *binary_name, char *const binary_argv[], GNUNET_MessageTokenizerCallback cb, GNUNET_HELPER_ExceptionCallback exp_cb, void *cb_cls)
Starts a helper and begins reading from it.
Definition: helper.c:491
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_array_append(arr, len, element)
Append an element to an array (growing the array by one).
#define GNUNET_free(ptr)
Wrapper around free.
char * GNUNET_OS_get_libexec_binary_path(const char *progname)
Given the name of a gnunet-helper, gnunet-service or gnunet-daemon binary, try to prefix it with the ...
int GNUNET_OS_check_helper_binary(const char *binary, int check_suid, const char *params)
Check whether an executable exists and possibly if the suid bit is set on the file.
#define GNUNET_MESSAGE_TYPE_CMDS_HELPER_ALL_PEERS_STARTED
#define GNUNET_MESSAGE_TYPE_CMDS_HELPER_LOCAL_FINISHED
#define GNUNET_MESSAGE_TYPE_CMDS_HELPER_PEER_STARTED
#define GNUNET_MESSAGE_TYPE_CMDS_HELPER_REPLY
The reply message from gnunet-cmds-helper.
#define GNUNET_MESSAGE_TYPE_CMDS_HELPER_INIT
The initialization message towards gnunet-cmds-helper.
void(* GNUNET_SCHEDULER_TaskCallback)(void *cls)
Signature of the main function of a task.
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_CMDS_HELPER_ALL_PEERS_STARTED.
Definition: testing_cmds.h:77
Initialization message for gnunet-cmds-testbed to start cmd binary.
Definition: testing_cmds.h:38
The handle to a helper process.
Definition: helper.c:79
Entry in the queue of messages we need to transmit to the helper.
Definition: helper.c:37
Header for all communications.
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
A command to be run by the interpreter.
int(* traits)(void *cls, const void **ret, const char *trait, unsigned int index)
Extract information from a command that is useful for other commands.
const char * label
Label for the command.
void * cls
Closure for all commands with command-specific context information.
Global state of the interpreter, used by a command to access information about other commands.
Definition: testing.h:35
unsigned int index
Index number associated with the trait.
Struct to store messages send/received by the helper into a DLL.
struct HelperMessage * prev
Kept in a DLL.
struct HelperMessage * next
Kept in a DLL.
uint16_t bytes_msg
Size of the original message.
Struct to hold information for callbacks.
unsigned int n_helper
Size of the array NetJailState::helper.
unsigned int n_shandle
Size of the array NetJailState::shandle.
unsigned int n_msg
Size of the array NetJailState::msg.
unsigned int number_of_peers_started
Number of peers started.
char * local_m
Number of nodes in a network namespace.
struct TestingSystemCount * tbcs_head
HEAD of the DLL containing TestingSystemCount.
unsigned int number_of_testsystems_started
Number of test environments started.
struct GNUNET_MessageHeader ** msg
The messages send to the helper.
char * plugin_name
Name of the test case plugin the helper will load.
struct HelperMessage * hp_messages_head
Head of the DLL which stores messages received by the helper.
struct GNUNET_HELPER_SendHandle ** shandle
The send handle for the helper.
struct TestingSystemCount * tbcs_tail
TAIL of the DLL containing TestingSystemCount.
unsigned int * rv
Pointer to the return value of the test.
char * global_n
Number of network namespaces.
struct GNUNET_HELPER_Handle ** helper
Array with handles of helper processes.
struct HelperMessage * hp_messages_tail
Tail of the DLL which stores messages received by the helper.
unsigned int number_of_local_test_finished
Number of local tests finished.
Struct containing the number of the test environment and the NetJailState which will be handed to cal...
unsigned int count
The number of the test environment.
struct TestingSystemCount * next
Kept in a DLL.
struct NetJailState * ns
Struct to store information handed over to callbacks.
struct TestingSystemCount * prev
Kept in a DLL.
static int netjail_exec_traits(void *cls, const void **ret, const char *trait, unsigned int index)
This function prepares an array with traits.
static void exp_cb(void *cls)
Callback called if there was an exception during execution of the helper.
static void clear_msg(void *cls, int result)
Continuation function from GNUNET_HELPER_send()
static void start_helper(struct NetJailState *ns, struct GNUNET_CONFIGURATION_Handle *config, char *m_char, char *n_char)
Function which start a single helper process.
static int netjail_start_finish(void *cls, GNUNET_SCHEDULER_TaskCallback cont, void *cont_cls)
This function checks on three different information.
static void netjail_exec_run(void *cls, const struct GNUNET_TESTING_Command *cmd, struct GNUNET_TESTING_Interpreter *is)
This function starts a helper process for each node.
static struct GNUNET_CMDS_HelperInit * create_helper_init_msg_(char *m_char, char *n_char, const char *plugin_name)
Function to initialize a init message for the helper.
static int helper_mst(void *cls, const struct GNUNET_MessageHeader *message)
Functions with this signature are called whenever a complete message is received by the tokenizer.
static void netjail_exec_cleanup(void *cls, const struct GNUNET_TESTING_Command *cmd)
Code to clean up resource this cmd used.
struct GNUNET_TESTING_Command GNUNET_TESTING_cmd_netjail_start_testing_system(const char *label, char *local_m, char *global_n, char *plugin_name, unsigned int *rv)
Create command.
int GNUNET_TESTING_get_trait_helper_handles(const struct GNUNET_TESTING_Command *cmd, struct GNUNET_HELPER_Handle ***helper)
Offer handles to testing cmd helper from trait.
struct GNUNET_TESTING_Interpreter * is
Message formats for communication between testing cmds helper and testcase plugins.
#define HELPER_CMDS_BINARY
Definition: testing_cmds.h:30