GNUnet  0.11.x
testing_api_cmd_netjail_start_testsystem_v2.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_v2.sh"
31 
36 struct HelperMessage
37 {
38 
42  struct HelperMessage *next;
43 
47  struct HelperMessage *prev;
48 
52  uint16_t bytes_msg;
53 
54  /* Followed by @e bytes_msg of msg.*/
55 };
56 
57 
62 struct NetJailState
63 {
68 
73  unsigned int *rv;
74 
80 
86 
91 
96  unsigned int n_helper;
97 
102  unsigned int local_m;
103 
108  unsigned int global_n;
109 
114  unsigned int known;
115 
120 
125  unsigned int n_shandle;
126 
130  struct GNUNET_MessageHeader **msg;
131 
136  unsigned int n_msg;
137 
142  unsigned int number_of_testsystems_started;
143 
148  unsigned int number_of_peers_started;
149 
154  unsigned int number_of_local_test_finished;
155 
160  char *plugin_name;
161 
167 
173 };
174 
179 struct TestingSystemCount
180 {
184  struct TestingSystemCount *next;
185 
189  struct TestingSystemCount *prev;
190 
195  unsigned int count;
196 
201  struct NetJailState *ns;
202 };
203 
210 static void
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 
240 static int
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  },
263  };
264 
265  return GNUNET_TESTING_get_trait (traits,
266  ret,
267  trait,
268  index);
269 }
270 
271 
279 int
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 
300 static void
301 clear_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 
325 static int
326 helper_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  }
337  message->type))
338  {
339  ns->number_of_peers_started++;
340  }
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 
363 static void
364 exp_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 
380 static struct GNUNET_CMDS_HelperInit *
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);
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 
405 static void
406 start_helper (struct NetJailState *ns, struct
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,
446  global_n_char,
447  local_m_char,
448  node_id,
449  NULL};
450 
451  unsigned int helper_check = GNUNET_OS_check_helper_binary (
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  {
470  "No SUID for %s!\n",
472  *ns->rv = 1;
473  }
474  else if (GNUNET_NO == helper_check)
475  {
477  "%s not found!\n",
479  *ns->rv = 1;
480  }
481 
482  GNUNET_array_append (ns->helper, ns->n_helper, GNUNET_HELPER_start (
483  GNUNET_YES,
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 
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  {
553  "Send handle is NULL!\n");
554  GNUNET_free (msg);
555  *ns->rv = 1;
556  }
557 }
558 
559 
567 static void
568 netjail_exec_run (void *cls,
569  const struct GNUNET_TESTING_Command *cmd,
571 {
572  struct NetJailState *ns = cls;
575 
576  for (int i = 1; i <= ns->known; i++)
577  {
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  {
588  j,
589  i);
590  }
591  }
592 }
593 
594 
595 static void
596 send_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 (
617  reply->header.size = htons ((uint16_t) msg_length);
618 
619  GNUNET_array_append (ns->msg, ns->n_msg, &reply->header);
620 
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 
641 static int
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 
692  const char *topology_config,
693  unsigned int *rv)
694 {
695  struct NetJailState *ns;
696 
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 }
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
enum GNUNET_TESTBED_TopologyOption topology
The topology to generate.
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
struct Plugin * plugin
The process handle to the testbed service.
static int result
Global testing status.
static char * plugin_name
Name of our plugin.
static const struct GNUNET_CONFIGURATION_Handle * config
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
#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_TESTING_NetjailTopology * GNUNET_TESTING_get_topo_from_file(const char *filename)
Getting the topology from file.
Definition: testing.c:1898
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.
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition: crypto_hash.c:41
void * GNUNET_CONTAINER_multishortmap_get(const struct GNUNET_CONTAINER_MultiShortmap *map, const struct GNUNET_ShortHashCode *key)
Given a key find a value in the map matching the key.
int GNUNET_CONTAINER_multishortmap_contains(const struct GNUNET_CONTAINER_MultiShortmap *map, const struct GNUNET_ShortHashCode *key)
Check if the map contains any value under the given key (including values that are NULL).
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
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#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
GNUNET_HELPER_Continuation cont
Function to call upon completion.
Definition: helper.c:61
void * cont_cls
Closure to 'cont'.
Definition: helper.c:66
A 512-bit hashcode.
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 256-bit hashcode.
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
Node in the netjail topology.
char * plugin
Plugin for the test case to be run on this node.
Toplogy of our netjail setup.
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.
struct GNUNET_TESTING_NetjailTopology * topology
The complete topology infomation.
unsigned int n_msg
Size of the array NetJailState::msg.
unsigned int number_of_peers_started
Number of peers started.
unsigned int local_m
Number of nodes in a natted subnet.
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.
unsigned int known
Number of global known nodes.
unsigned int global_n
Number of natted subnets.
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 struct GNUNET_CMDS_HelperInit * create_helper_init_msg_(const char *plugin_name)
Function to initialize a init message for the helper.
struct GNUNET_TESTING_Command GNUNET_TESTING_cmd_netjail_start_testing_system_v2(const char *label, const char *topology_config, unsigned int *rv)
Create command.
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 void send_all_peers_started(unsigned int i, unsigned int j, struct NetJailState *ns)
int GNUNET_TESTING_get_trait_helper_handles_v2(const struct GNUNET_TESTING_Command *cmd, struct GNUNET_HELPER_Handle ***helper)
Offer handles to testing cmd helper from trait.
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.
static void start_helper(struct NetJailState *ns, struct GNUNET_CONFIGURATION_Handle *config, unsigned int m, unsigned int n)
Function which start a single helper process.
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