GNUnet  0.11.x
testbed_api_cmd_netjail_start_testbed.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"
29 #include "testbed_api.h"
30 #include "testbed_api_hosts.h"
31 #include "testbed_helper.h"
32 
33 #define NETJAIL_EXEC_SCRIPT "./../testbed/netjail_exec.sh"
34 
35 struct HelperMessage;
36 
38 {
39 
41 
43 
47  uint16_t bytes_msg;
48 
49  /* Followed by @e bytes_msg of msg.*/
50 };
51 
52 
53 
54 struct NetJailState
55 {
56 
58 
60 
65 
66  unsigned int n_helper;
67 
68  char *binary_name;
69 
70  char *local_m;
71 
72  char *global_n;
73 
78 
79  unsigned int n_shandle;
80 
85 
86  unsigned int n_msg;
87 
89 
91 
93 
98 
99  unsigned int n_host;
100 
101  char *plugin_name;
102 };
103 
105 {
106  unsigned int count;
107 
108  struct NetJailState *ns;
109 };
110 
117 static void
119  const struct GNUNET_TESTING_Command *cmd)
120 {
121  struct NetJailState *ns = cls;
122 
123  GNUNET_free (ns->binary_name);
124 }
125 
126 
136 static int
138  const void **ret,
139  const char *trait,
140  unsigned int index)
141 {
142  struct NetJailState *ns = cls;
143  struct GNUNET_HELPER_Handle **helper = ns->helper;
144  struct HelperMessage *hp_messages_head = ns->hp_messages_head;
145 
146 
147  struct GNUNET_TESTING_Trait traits[] = {
148  {
149  .index = 0,
150  .trait_name = "helper_handles",
151  .ptr = (const void *) helper,
152  },
153  {
154  .index = 1,
155  .trait_name = "hp_msgs_head",
156  .ptr = (const void *) hp_messages_head,
157  },
159  };
160 
161  return GNUNET_TESTING_get_trait (traits,
162  ret,
163  trait,
164  index);
165 }
166 
167 
175 int
178  struct GNUNET_HELPER_Handle ***helper)
179 {
180  return cmd->traits (cmd->cls,
181  (const void **) helper,
182  "helper_handles",
183  (unsigned int) 0);
184 }
185 
193 int
196  struct HelperMessage ***
197  hp_messages_head)
198 {
199  return cmd->traits (cmd->cls,
200  (const void **) hp_messages_head,
201  "hp_msgs_head",
202  (unsigned int) 1);
203 }
204 
205 
214 static void
215 clear_msg (void *cls, int result)
216 {
217  struct TestbedCount *tbc = cls;
218  struct NetJailState *ns = tbc->ns;
219 
221  "clear_msg tbc->count: %d\n",
222  tbc->count);
223  GNUNET_assert (NULL != ns->shandle[tbc->count - 1]);
224  ns->shandle[tbc->count - 1] = NULL;
225  GNUNET_free (ns->msg[tbc->count - 1]);
226  ns->msg[tbc->count - 1] = NULL;
227 }
228 
229 
242 static int
243 helper_mst (void *cls, const struct GNUNET_MessageHeader *message)
244 {
245  struct TestbedCount *tbc = cls;
246  struct NetJailState *ns = tbc->ns;
247  struct HelperMessage *hp_msg;
248 
249  if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_REPLY == ntohs (message->type))
250  {
252  "helper_mst tbc->count: %d\n",
253  tbc->count);
254  // GNUNET_TESTBED_extract_cfg (host, message);
256  "Received message from helper.\n");
257  ns->number_of_testbeds_started++;
258  }
260  message->type))
261  {
262  ns->number_of_peers_started++;
264  "number_of_peers_started: %d\n",
265  ns->number_of_peers_started);
266  }
268  message->type))
269  {
270  ns->number_of_local_test_finished++;
271  }
272  else
273  {
274  hp_msg = GNUNET_new (struct HelperMessage);
275  hp_msg->bytes_msg = message->size;
276  memcpy (&hp_msg[1], message, message->size);
277  GNUNET_CONTAINER_DLL_insert (ns->hp_messages_head, ns->hp_messages_tail,
278  hp_msg);
279  }
280 
281  return GNUNET_OK;
282 }
283 
284 
285 static void
286 exp_cb (void *cls)
287 {
288  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called exp_cb.\n");
290 }
291 
292 
293 static struct GNUNET_CMDS_HelperInit *
295  char *n_char,
296  const char *plugin_name)
297 {
298  struct GNUNET_CMDS_HelperInit *msg;
299  uint16_t plugin_name_len;
300  uint16_t msg_size;
301 
302  GNUNET_assert (NULL != plugin_name);
303  plugin_name_len = strlen (plugin_name);
304  msg_size = sizeof(struct GNUNET_CMDS_HelperInit) + plugin_name_len;
306  "msg_size: %d \n",
307  msg_size);
308  msg = GNUNET_malloc (msg_size);
309  msg->header.size = htons (msg_size);
311  msg->plugin_name_size = htons (plugin_name_len);
312  GNUNET_memcpy ((char *) &msg[1],
313  plugin_name,
314  plugin_name_len);
315  return msg;
316 }
317 
318 
319 static void
320 start_testbed (struct NetJailState *ns, struct
322  char *m_char,
323  char *n_char)
324 {
325  // struct GNUNET_CONFIGURATION_Handle *cfg;
326  struct GNUNET_CMDS_HelperInit *msg;
327  struct TestbedCount *tbc;
328  char *const script_argv[] = {NETJAIL_EXEC_SCRIPT,
329  m_char,
330  n_char,
333  ns->global_n,
334  ns->local_m,
335  NULL};
336  unsigned int m = atoi (m_char);
337  unsigned int n = atoi (n_char);
338 
340  "m: %d n: %d\n",
341  m,
342  n);
343 
344  tbc = GNUNET_new (struct TestbedCount);
345  tbc->ns = ns;
346  tbc->count = (n - 1) * atoi (ns->local_m) + m;
347 
348  // cfg = GNUNET_CONFIGURATION_dup (config);
349 
350  // TODO We do not need this?
351  /*GNUNET_array_append (ns->host, ns->n_host,
352  GNUNET_TESTBED_host_create_with_id (tbc->count - 1,
353  NULL,
354  NULL,
355  cfg,
356  0));*/
357 
358  /*if ((GNUNET_YES != GNUNET_DISK_file_test ("test_testbed_api.conf")) ||
359  (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (config,
360  "test_testbed_api.conf")))
361  {
362  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
363  _ (
364  "Unreadable or malformed configuration file `%s', exit ...\n"),
365  "test_testbed_api.conf");
366  }*/
367 
368  GNUNET_array_append (ns->helper, ns->n_helper, GNUNET_HELPER_start (
369  GNUNET_YES,
371  script_argv,
372  &helper_mst,
373  &exp_cb,
374  tbc));
375 
376  struct GNUNET_HELPER_Handle *helper = ns->helper[tbc->count - 1];
377 
378  msg = create_helper_init_msg_ (m_char,
379  n_char,
380  ns->plugin_name);
381  GNUNET_array_append (ns->msg, ns->n_msg, &msg->header);
382 
383  GNUNET_array_append (ns->shandle, ns->n_shandle, GNUNET_HELPER_send (
384  helper,
385  &msg->header,
386  GNUNET_NO,
387  &clear_msg,
388  tbc));
389 
391  "Message %d send!\n",
392  tbc->count);
393 
394  if (NULL == ns->shandle[tbc->count - 1])
395  {
397  "Send handle is NULL!\n");
398  GNUNET_free (msg);
400  }
401 }
402 
403 
411 static void
412 netjail_exec_run (void *cls,
413  const struct GNUNET_TESTING_Command *cmd,
415 {
416  char str_m[12];
417  char str_n[12];
418  struct NetJailState *ns = cls;
421 
422  for (int i = 1; i <= atoi (ns->global_n); i++) {
423  for (int j = 1; j <= atoi (ns->local_m); j++)
424  {
425  sprintf (str_n, "%d", i);
426  sprintf (str_m, "%d", j);
428  str_m,
429  str_n);
430  }
431  }
432 }
433 
434 
435 static int
438  void *cont_cls)
439 {
440  unsigned int ret = GNUNET_NO;
441  struct NetJailState *ns = cls;
442  unsigned int total_number = atoi (ns->local_m) * atoi (ns->global_n);
443  struct GNUNET_CMDS_ALL_PEERS_STARTED *reply;
444  size_t msg_length;
445  struct GNUNET_HELPER_Handle *helper;
446  struct TestbedCount *tbc;
447 
448  if (ns->number_of_local_test_finished == total_number)
449  {
450  ret = GNUNET_YES;
451  cont (cont_cls);
452  }
453 
454  if (ns->number_of_testbeds_started == total_number)
455  {
457  "All helpers started!\n");
458  ns->number_of_testbeds_started = 0;
459  }
460 
461  if (ns->number_of_peers_started == total_number)
462  {
464  "All peers started!\n");
465 
466  for (int i = 1; i <= atoi (ns->global_n); i++) {
467  for (int j = 1; j <= atoi (ns->local_m); j++)
468  {
469  tbc = GNUNET_new (struct TestbedCount);
470  tbc->ns = ns;
471  // 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.
472  tbc->count = (j - 1) * atoi (ns->local_m) + i + total_number;
473  helper = ns->helper[tbc->count - 1 - total_number];
474  msg_length = sizeof(struct GNUNET_CMDS_ALL_PEERS_STARTED);
475  reply = GNUNET_new (struct GNUNET_CMDS_ALL_PEERS_STARTED);
476  reply->header.type = htons (
478  reply->header.size = htons ((uint16_t) msg_length);
479 
480  GNUNET_array_append (ns->msg, ns->n_msg, &reply->header);
481 
483  helper,
484  &reply->header,
485  GNUNET_NO,
486  &clear_msg,
487  tbc);
488 
489  GNUNET_array_append (ns->shandle, ns->n_shandle, sh);
490 
492  "All peers started message %d send!\n",
493  tbc->count);
494  }
495  }
496  ns->number_of_peers_started = 0;
497  }
498  return ret;
499 }
500 
501 
511  char *local_m,
512  char *global_n,
513  char *plugin_name)
514 {
515  struct NetJailState *ns;
516 
517  ns = GNUNET_new (struct NetJailState);
518  ns->local_m = local_m;
519  ns->global_n = global_n;
520  ns->plugin_name = plugin_name;
521 
522  struct GNUNET_TESTING_Command cmd = {
523  .cls = ns,
524  .label = label,
525  .run = &netjail_exec_run,
526  .finish = &netjail_start_finish,
527  .cleanup = &netjail_exec_cleanup,
528  .traits = &netjail_exec_traits
529  };
530 
531  return cmd;
532 }
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:87
@ GNUNET_YES
Definition: gnunet_common.h:89
@ GNUNET_NO
Definition: gnunet_common.h:86
void GNUNET_TESTING_interpreter_fail()
Current command failed, clean up and fail the test case.
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_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 ...
#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_TESTING_Command GNUNET_TESTBED_cmd_netjail_start_testbed(const char *label, char *local_m, char *global_n, char *plugin_name)
Create command.
int GNUNET_TESTBED_get_trait_helper_handles(const struct GNUNET_TESTING_Command *cmd, struct GNUNET_HELPER_Handle ***helper)
Offer handles to testbed helper from trait.
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_CMDS_HELPER_ALL_PEERS_STARTED.
Initialization message for gnunet-cmds-testbed to start cmd binary.
configuration data
Definition: configuration.c:85
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.
Opaque handle to a host running experiments managed by the testing framework.
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.
uint16_t bytes_msg
Size of the original message.
struct GNUNET_HELPER_Handle ** helper
The process handle.
struct HelperMessage * hp_messages_head
struct GNUNET_HELPER_SendHandle ** shandle
The send handle for the helper.
struct GNUNET_MessageHeader ** msg
The message corresponding to send handle.
struct GNUNET_TESTBED_Host ** host
The host where the controller is running.
struct HelperMessage * hp_messages_tail
Interface for functions internally exported from testbed_api.c.
#define HELPER_CMDS_BINARY
Cmds Helper binary name.
Definition: testbed_api.h:43
static int netjail_exec_traits(void *cls, const void **ret, const char *trait, unsigned int index)
static void exp_cb(void *cls)
static void clear_msg(void *cls, int result)
Continuation function from GNUNET_HELPER_send()
int GNUNET_TESTBED_get_trait_helper_messages(const struct GNUNET_TESTING_Command *cmd, struct HelperMessage ***hp_messages_head)
Offer handles to testbed helper from trait.
static int netjail_start_finish(void *cls, GNUNET_SCHEDULER_TaskCallback cont, void *cont_cls)
static void netjail_exec_run(void *cls, const struct GNUNET_TESTING_Command *cmd, struct GNUNET_TESTING_Interpreter *is)
Run the "hello world" CMD.
static struct GNUNET_CMDS_HelperInit * create_helper_init_msg_(char *m_char, char *n_char, const char *plugin_name)
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)
static void start_testbed(struct NetJailState *ns, struct GNUNET_CONFIGURATION_Handle *config, char *m_char, char *n_char)
internal API to access the 'hosts' subsystem
Message formats for communication between testbed api and gnunet-helper-testbed process.
struct GNUNET_TESTING_Interpreter * is