GNUnet  0.11.x
gnunet-cmds-helper.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 
39 #include "platform.h"
40 #include "gnunet_util_lib.h"
41 #include "gnunet_testing_lib.h"
42 #include "gnunet_testing_ng_lib.h"
43 #include "testing_cmds.h"
44 #include "gnunet_testing_plugin.h"
45 #include <zlib.h>
46 
47 
51 #define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
52 
56 #define LOG_DEBUG(...) LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
57 
58 #define NODE_BASE_IP "192.168.15."
59 
60 #define KNOWN_BASE_IP "92.68.151."
61 
62 #define ROUTER_BASE_IP "92.68.150."
63 
67 struct Plugin
68 {
72  char *library_name;
73 
78 
83  char *node_ip;
84 
89  char *plugin_name;
90 
95  char *global_n;
96 
101  char *local_m;
102 
107  char *n;
108 
113  char *m;
114 };
115 
121 {
126  char *n;
127 
132  char *m;
133 
138  char *global_n;
139 
144  char *local_m;
145 
149  unsigned int *read_file;
150 
155 };
156 
160 struct WriteContext
161 {
165  void *data;
166 
170  size_t length;
171 
175  size_t pos;
176 };
177 
186 struct Plugin *plugin;
187 
192 
197 
202 
207 
212 
217 
221 static int done_reading;
222 
226 static int status;
227 
228 
234 static void
235 shutdown_task (void *cls)
236 {
237 
238  LOG_DEBUG ("Shutting down.\n");
239 
240  if (NULL != read_task_id)
241  {
243  read_task_id = NULL;
244  }
245  if (NULL != write_task_id)
246  {
247  struct WriteContext *wc;
248 
250  write_task_id = NULL;
251  GNUNET_free (wc->data);
252  GNUNET_free (wc);
253  }
254  if (NULL != stdin_fd)
256  if (NULL != stdout_fd)
259  tokenizer = NULL;
260 }
261 
262 
268 static void
269 write_task (void *cls)
270 {
271  struct WriteContext *wc = cls;
272  ssize_t bytes_wrote;
273 
274  GNUNET_assert (NULL != wc);
275  write_task_id = NULL;
276  bytes_wrote = GNUNET_DISK_file_write (stdout_fd,
277  wc->data + wc->pos,
278  wc->length - wc->pos);
279  if (GNUNET_SYSERR == bytes_wrote)
280  {
282  "Cannot reply back successful initialization\n");
283  GNUNET_free (wc->data);
284  GNUNET_free (wc);
285  return;
286  }
287  wc->pos += bytes_wrote;
288  if (wc->pos == wc->length)
289  {
290  GNUNET_free (wc->data);
291  GNUNET_free (wc);
292  return;
293  }
295  stdout_fd,
296  &write_task,
297  wc);
298 }
299 
300 
305 static void
306 write_message (struct GNUNET_MessageHeader *message, size_t msg_length)
307 {
308  struct WriteContext *wc;
309 
310  wc = GNUNET_new (struct WriteContext);
311  wc->length = msg_length;
312  wc->data = message;
315  stdout_fd,
316  &write_task,
317  wc);
318 }
319 
320 
333 static int
334 tokenizer_cb (void *cls, const struct GNUNET_MessageHeader *message)
335 {
336 
337  struct NodeIdentifier *ni = cls;
338  const struct GNUNET_CMDS_HelperInit *msg;
339  struct GNUNET_CMDS_HelperReply *reply;
340  char *binary;
341  char *plugin_name;
342  size_t plugin_name_size;
343  uint16_t msize;
344  size_t msg_length;
345  char *router_ip;
346  char *node_ip;
347  unsigned int namespace_n;
348 
349  msize = ntohs (message->size);
350  if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_INIT == ntohs (message->type))
351  {
352  msg = (const struct GNUNET_CMDS_HelperInit *) message;
353  plugin_name_size = ntohs (msg->plugin_name_size);
354  if ((sizeof(struct GNUNET_CMDS_HelperInit) + plugin_name_size) > msize)
355  {
356  GNUNET_break (0);
358  "Received unexpected message -- exiting\n");
359  goto error;
360  }
363  ((char *) &msg[1]),
364  plugin_name_size + 1);
365 
366  binary = GNUNET_OS_get_libexec_binary_path ("gnunet-cmd");
367 
368  plugin = GNUNET_new (struct Plugin);
370  NULL);
372 
373  plugin->global_n = ni->global_n;
374  plugin->local_m = ni->local_m;
375  plugin->n = ni->n;
376  plugin->m = ni->m;
377 
378  router_ip = GNUNET_malloc (strlen (ROUTER_BASE_IP) + strlen (plugin->n)
379  + 1);
380  strcpy (router_ip, ROUTER_BASE_IP);
381  strcat (router_ip, plugin->n);
382 
383  sscanf (plugin->n, "%u", &namespace_n);
384 
385  if (0 == namespace_n)
386  {
388  "known node n: %s\n",
389  plugin->n);
390  node_ip = GNUNET_malloc (strlen (KNOWN_BASE_IP) + strlen (plugin->m) + 1);
391  strcat (node_ip, KNOWN_BASE_IP);
392  }
393  else
394  {
396  "subnet node n: %s\n",
397  plugin->n);
398  node_ip = GNUNET_malloc (strlen (NODE_BASE_IP) + strlen (plugin->m) + 1);
399  strcat (node_ip, NODE_BASE_IP);
400  }
401  strcat (node_ip, plugin->m);
402 
403  plugin->api->start_testcase (&write_message, router_ip, node_ip, plugin->m,
405  ni->read_file);
406 
407  msg_length = sizeof(struct GNUNET_CMDS_HelperReply);
408  reply = GNUNET_new (struct GNUNET_CMDS_HelperReply);
410  reply->header.size = htons ((uint16_t) msg_length);
411 
412  write_message ((struct GNUNET_MessageHeader *) reply, msg_length);
413 
414  GNUNET_free (binary);
415  GNUNET_free (router_ip);
417 
418  return GNUNET_OK;
419  }
421  message->type))
422  {
424  "all peers started\n");
425  plugin->api->all_peers_started ();
426  return GNUNET_OK;
427  }
429  message->type))
430  {
432  "all local tests prepared\n");
433  plugin->api->all_local_tests_prepared ();
434  return GNUNET_OK;
435  }
436  else
437  {
438  LOG (GNUNET_ERROR_TYPE_WARNING, "Received unexpected message -- exiting\n");
439  goto error;
440  }
441 
442 
443  error:
446  "tokenizer shutting down!\n");
448  return GNUNET_SYSERR;
449 }
450 
451 
457 static void
458 read_task (void *cls)
459 {
461  ssize_t sread;
462 
463  read_task_id = NULL;
464  sread = GNUNET_DISK_file_read (stdin_fd, buf, sizeof(buf));
465  if ((GNUNET_SYSERR == sread) || (0 == sread))
466  {
467  LOG_DEBUG ("STDIN closed\n");
469  return;
470  }
471  if (GNUNET_YES == done_reading)
472  {
473  /* didn't expect any more data! */
474  GNUNET_break_op (0);
476  "tokenizer shutting down during reading, didn't expect any more data!\n");
478  return;
479  }
480  LOG_DEBUG ("Read %u bytes\n", (unsigned int) sread);
481  /* FIXME: could introduce a GNUNET_MST_read2 to read
482  directly from 'stdin_fd' and save a memcpy() here */
483  if (GNUNET_OK !=
485  {
486  GNUNET_break (0);
488  "tokenizer shutting down during reading, writing to buffer failed!\n");
490  return;
491  }
492  read_task_id /* No timeout while reading */
494  stdin_fd,
495  &read_task,
496  NULL);
497 }
498 
499 
508 static void
509 run (void *cls,
510  char *const *args,
511  const char *cfgfile,
512  const struct GNUNET_CONFIGURATION_Handle *cfg)
513 {
514  struct NodeIdentifier *ni = cls;
515 
516  LOG_DEBUG ("Starting interpreter loop helper...\n");
517 
522  stdin_fd,
523  &read_task,
524  NULL);
526 }
527 
528 
532 static void
534 {
535  static char c;
536  int old_errno; /* back-up errno */
537 
538  old_errno = errno;
539  GNUNET_break (
540  1 ==
543  &c,
544  sizeof(c)));
545  errno = old_errno;
546 }
547 
548 
556 int
557 main (int argc, char **argv)
558 {
559  struct NodeIdentifier *ni;
563  int ret;
564  int i;
565  size_t topology_data_length = 0;
566  unsigned int read_file;
567  char cr[1] = "\n";
568 
569  GNUNET_log_setup ("gnunet-cmds-helper",
570  "DEBUG",
571  NULL);
572  ni = GNUNET_new (struct NodeIdentifier);
573  ni->global_n = argv[1];
574  ni->local_m = argv[2];
575  ni->m = argv[3];
576  ni->n = argv[4];
577 
578  sscanf (argv[5], "%u", &read_file);
579 
580  if (1 == read_file)
581  ni->topology_data = argv[6];
582  else
583  {
584  for (i = 6; i<argc; i++)
585  topology_data_length += strlen (argv[i]) + 1;
587  "topo data length %lu\n",
588  topology_data_length);
589  ni->topology_data = GNUNET_malloc (topology_data_length);
590  for (i = 6; i<argc; i++)
591  {
592  strcat (ni->topology_data, argv[i]);
593  strcat (ni->topology_data, cr);
594  }
595  }
596  ni->read_file = &read_file;
597  ni->topology_data[topology_data_length - 1] = '\0';
599  "topo data %s\n",
600  ni->topology_data);
601 
602  status = GNUNET_OK;
603  if (NULL ==
605  {
606  GNUNET_break (0);
607  return 1;
608  }
609  shc_chld =
611  ret = GNUNET_PROGRAM_run (argc,
612  argv,
613  "gnunet-cmds-helper",
614  "Helper for starting a local interpreter loop",
615  options,
616  &run,
617  ni);
618 
620  shc_chld = NULL;
622  GNUNET_free (ni);
623  if (GNUNET_OK != ret)
624  return 1;
625  return (GNUNET_OK == status) ? 0 : 1;
626 }
627 
628 
629 /* end of gnunet-cmds-helper.c */
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_OPTION_END
Definition: 002.c:13
struct GNUNET_GETOPT_CommandLineOption options[]
Definition: 002.c:5
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
static struct GNUNET_SIGNAL_Context * shc_chld
static const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration we are using.
Definition: gnunet-abd.c:36
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static void write_message(struct GNUNET_MessageHeader *message, size_t msg_length)
Callback to write a message to the master loop.
struct GNUNET_MessageStreamTokenizer * tokenizer
Our message stream tokenizer.
static void read_task(void *cls)
Task to read from stdin.
int main(int argc, char **argv)
Main function.
static struct GNUNET_DISK_FileHandle * stdout_fd
Disk handle for stdout.
static void shutdown_task(void *cls)
Task to shut down cleanly.
static int status
Result to return in case we fail.
static int tokenizer_cb(void *cls, const struct GNUNET_MessageHeader *message)
Functions with this signature are called whenever a complete message is received by the tokenizer.
#define LOG_DEBUG(...)
Debug logging shorthand.
static struct GNUNET_DISK_PipeHandle * sigpipe
Pipe used to communicate shutdown via signal.
static void sighandler_child_death()
Signal handler called for SIGCHLD.
#define NODE_BASE_IP
struct Plugin * plugin
The process handle to the testbed service.
static struct GNUNET_SCHEDULER_Task * read_task_id
Task identifier for the read task.
#define ROUTER_BASE_IP
static void write_task(void *cls)
Task to write to the standard out.
#define KNOWN_BASE_IP
static void run(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
Main function that will be run.
#define LOG(kind,...)
Generic logging shortcut testing_api_cmd_block_until_all_peers_started.c.
static struct GNUNET_SCHEDULER_Task * write_task_id
Task identifier for the write task.
static struct GNUNET_DISK_FileHandle * stdin_fd
Disk handle from stdin.
static int done_reading
Are we done reading messages from stdin?
static char * plugin_name
Name of our plugin.
static char buf[2048]
@ GNUNET_OK
Definition: gnunet_common.h:95
@ GNUNET_YES
Definition: gnunet_common.h:97
@ GNUNET_NO
Definition: gnunet_common.h:94
@ GNUNET_SYSERR
Definition: gnunet_common.h:93
#define GNUNET_MAX_MESSAGE_SIZE
Largest supported message (to be precise, one byte more than the largest possible message,...
struct GNUNET_DISK_FileHandle * GNUNET_DISK_get_handle_from_native(FILE *fd)
Get a handle from a native FD.
Definition: disk.c:1344
ssize_t GNUNET_DISK_file_write(const struct GNUNET_DISK_FileHandle *h, const void *buffer, size_t n)
Write a buffer to a file.
Definition: disk.c:686
enum GNUNET_GenericReturnValue GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition: disk.c:1585
enum GNUNET_GenericReturnValue GNUNET_DISK_file_close(struct GNUNET_DISK_FileHandle *h)
Close an open file.
Definition: disk.c:1306
ssize_t GNUNET_DISK_file_read(const struct GNUNET_DISK_FileHandle *h, void *result, size_t len)
Read the contents of a binary file into a buffer.
Definition: disk.c:622
const struct GNUNET_DISK_FileHandle * GNUNET_DISK_pipe_handle(const struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd n)
Get the handle to a particular pipe end.
Definition: disk.c:1616
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(enum GNUNET_DISK_PipeFlags pf)
Creates an interprocess channel.
Definition: disk.c:1442
@ GNUNET_DISK_PF_NONE
No special options, use non-blocking read/write operations.
@ GNUNET_DISK_PIPE_END_WRITE
The writing-end of a pipe.
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
int GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
Setup logging.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#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 ...
void * GNUNET_PLUGIN_load(const char *library_name, void *arg)
Setup plugin (runs the "init" callback and returns whatever "init" returned).
Definition: plugin.c:217
enum GNUNET_GenericReturnValue GNUNET_PROGRAM_run(int argc, char *const *argv, const char *binaryName, const char *binaryHelp, const struct GNUNET_GETOPT_CommandLineOption *options, GNUNET_PROGRAM_Main task, void *task_cls)
Run a standard GNUnet command startup sequence (initialize loggers and configuration,...
Definition: program.c:399
#define GNUNET_MESSAGE_TYPE_CMDS_HELPER_ALL_PEERS_STARTED
#define GNUNET_MESSAGE_TYPE_CMDS_HELPER_ALL_LOCAL_TESTS_PREPARED
#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_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:531
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_read_file(struct GNUNET_TIME_Relative delay, const struct GNUNET_DISK_FileHandle *rfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1667
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_write_file(struct GNUNET_TIME_Relative delay, const struct GNUNET_DISK_FileHandle *wfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1700
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition: scheduler.c:1331
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:972
void GNUNET_MST_destroy(struct GNUNET_MessageStreamTokenizer *mst)
Destroys a tokenizer.
Definition: mst.c:418
struct GNUNET_MessageStreamTokenizer * GNUNET_MST_create(GNUNET_MessageTokenizerCallback cb, void *cb_cls)
Create a message stream tokenizer.
Definition: mst.c:85
int GNUNET_MST_from_buffer(struct GNUNET_MessageStreamTokenizer *mst, const char *buf, size_t size, int purge, int one_shot)
Add incoming data to the receive buffer and call the callback for all complete messages.
Definition: mst.c:114
struct GNUNET_SIGNAL_Context * GNUNET_SIGNAL_handler_install(int signal, GNUNET_SIGNAL_Handler handler)
Install a signal handler that will be run if the given signal is received.
Definition: signal.c:51
void GNUNET_SIGNAL_handler_uninstall(struct GNUNET_SIGNAL_Context *ctx)
Uninstall a previously installed signal handler.
Definition: signal.c:77
size_t GNUNET_strlcpy(char *dst, const char *src, size_t n)
Like strlcpy but portable.
Definition: strings.c:139
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
enum GNUNET_GenericReturnValue read_file(char const *const filename, char **buffer)
Definition: pabc_helper.c:70
#define GNUNET_SIGCHLD
Definition: platform.h:42
Initialization message for gnunet-cmds-testbed to start cmd binary.
Definition: testing_cmds.h:38
Reply message from cmds helper process.
Definition: testing_cmds.h:57
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_CMDS_HELPER_REPLY.
Definition: testing_cmds.h:61
Handle used to access files (and pipes).
Handle used to manage a pipe.
Definition: disk.c:69
Definition of a command line option.
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.
Handle to a message stream tokenizer.
Definition: mst.c:44
Entry in list of pending tasks.
Definition: scheduler.c:135
Struct with information about a specific node and the whole network namespace setup.
unsigned int * read_file
Shall we read the topology from file, or from a string.
char * topology_data
String with topology data or name of topology file.
char * m
The number of the node in the namespace.
char * n
The number of the namespace this node is in.
char * local_m
The number of local nodes per namespace.
char * global_n
The number of namespaces.
Handle for a plugin.
Definition: block.c:38
struct GNUNET_BLOCK_PluginFunctions * api
Plugin API.
Definition: block.c:47
char * node_ip
IP address of the specific node the helper is running for.
char * m
The number of the node in the namespace.
char * n
The number of the namespace this node is in.
char * global_n
The number of namespaces.
struct GNUNET_TESTING_PluginFunctions * api
Plugin API.
char * plugin_name
Name of the test case plugin.
char * local_m
The number of local nodes per namespace.
char * library_name
Name of the shared library.
Definition: block.c:42
Context for a single write on a chunk of memory.
size_t pos
The current position from where the write operation should begin.
size_t length
The length of the data.
void * data
The data to write.
Message formats for communication between testing cmds helper and testcase plugins.