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) 2008--2013, 2016 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_testbed_service.h"
43 #include "testbed_helper.h"
44 #include "testbed_api.h"
45 #include "gnunet_testing_plugin.h"
46 #include <zlib.h>
47 
48 
52 #define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
53 
57 #define LOG_DEBUG(...) LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
58 
59 #define NODE_BASE_IP "192.168.15."
60 
61 #define ROUTER_BASE_IP "92.68.150."
62 
66 struct Plugin
67 {
71  char *library_name;
72 
77 
78  char *node_ip;
79 
80  char *plugin_name;
81 
82  char *global_n;
83 
84  char *local_m;
85 
86  char *n;
87 
88  char *m;
89 };
90 
92 {
93  char *n;
94 
95  char *m;
96 
97  char *global_n;
98 
99  char *local_m;
100 };
101 
106 {
110  void *data;
111 
115  size_t length;
116 
120  size_t pos;
121 };
122 
123 struct Plugin *plugin;
124 
134 
139 
144 
149 
154 
159 
164 
169 
173 static int done_reading;
174 
178 static int status;
179 
180 
186 static void
187 shutdown_task (void *cls)
188 {
189 
190  LOG_DEBUG ("Shutting down.\n");
192  "Shutting down tokenizer!\n");
193 
194  if (NULL != read_task_id)
195  {
196  GNUNET_SCHEDULER_cancel (read_task_id);
197  read_task_id = NULL;
198  }
199  if (NULL != write_task_id)
200  {
201  struct WriteContext *wc;
202 
203  wc = GNUNET_SCHEDULER_cancel (write_task_id);
204  write_task_id = NULL;
205  GNUNET_free (wc->data);
206  GNUNET_free (wc);
207  }
208  if (NULL != child_death_task_id)
209  {
210  GNUNET_SCHEDULER_cancel (child_death_task_id);
211  child_death_task_id = NULL;
212  }
213  if (NULL != stdin_fd)
214  (void) GNUNET_DISK_file_close (stdin_fd);
215  if (NULL != stdout_fd)
216  (void) GNUNET_DISK_file_close (stdout_fd);
217  GNUNET_MST_destroy (tokenizer);
218  tokenizer = NULL;
219 
220  if (NULL != test_system)
221  {
223  test_system = NULL;
224  }
225 }
226 
227 
233 static void
234 write_task (void *cls)
235 {
236  struct WriteContext *wc = cls;
237  ssize_t bytes_wrote;
238 
240  "Writing data!\n");
241 
242  GNUNET_assert (NULL != wc);
243  write_task_id = NULL;
244  bytes_wrote = GNUNET_DISK_file_write (stdout_fd,
245  wc->data + wc->pos,
246  wc->length - wc->pos);
247  if (GNUNET_SYSERR == bytes_wrote)
248  {
250  "Cannot reply back successful initialization\n");
251  GNUNET_free (wc->data);
252  GNUNET_free (wc);
253  return;
254  }
255  wc->pos += bytes_wrote;
256  if (wc->pos == wc->length)
257  {
258  GNUNET_free (wc->data);
259  GNUNET_free (wc);
261  "Written successfully!\n");
262  return;
263  }
265  "Written data!\n");
267  stdout_fd,
268  &write_task,
269  wc);
270 }
271 
272 
279 /*static void
280 child_death_task (void *cls)
281 {
282  const struct GNUNET_DISK_FileHandle *pr;
283  char c[16];
284 
285  pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
286  child_death_task_id = NULL;
287  // consume the signal
288  GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof(c)));
289  LOG_DEBUG ("Got SIGCHLD\n");
290 
291  LOG_DEBUG ("Child hasn't died. Resuming to monitor its status\n");
292  child_death_task_id =
293  GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
294  pr,
295  &child_death_task,
296  NULL);
297 }*/
298 
299 
300 static void
301 write_message (struct GNUNET_MessageHeader *message, size_t msg_length)
302 {
303  struct WriteContext *wc;
304 
306  "enter write_message!\n");
307  wc = GNUNET_new (struct WriteContext);
308  wc->length = msg_length;
309  wc->data = message;
310  write_task_id = GNUNET_SCHEDULER_add_write_file (
312  stdout_fd,
313  &write_task,
314  wc);
316  "leave write_message!\n");
317 }
318 
319 
326 /*static void
327 run_plugin (void *cls)
328 {
329  struct Plugin *plugin = cls;
330  char *router_ip;
331  char *node_ip;
332 
333  router_ip = GNUNET_malloc (strlen (ROUTER_BASE_IP) + strlen (plugin->m) + 1);
334  strcpy (router_ip, ROUTER_BASE_IP);
335  strcat (router_ip, plugin->m);
336 
337  node_ip = GNUNET_malloc (strlen (NODE_BASE_IP) + strlen (plugin->n) + 1);
338  strcat (node_ip, NODE_BASE_IP);
339  strcat (node_ip, plugin->n);
340 
341  plugin->api->start_testcase (&write_message, router_ip, node_ip);
342 
343 }*/
344 
345 
358 static int
359 tokenizer_cb (void *cls, const struct GNUNET_MessageHeader *message)
360 {
361  struct NodeIdentifier *ni = cls;
362  const struct GNUNET_CMDS_HelperInit *msg;
363  struct GNUNET_CMDS_HelperReply *reply;
364  char *binary;
365  char *plugin_name;
366  size_t plugin_name_size;
367  uint16_t msize;
368  size_t msg_length;
369  char *router_ip;
370  char *node_ip;
371 
373  "tokenizer \n");
374 
375  msize = ntohs (message->size);
376  if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_INIT == ntohs (message->type))
377  {
378  msg = (const struct GNUNET_CMDS_HelperInit *) message;
379  plugin_name_size = ntohs (msg->plugin_name_size);
380  if ((sizeof(struct GNUNET_CMDS_HelperInit) + plugin_name_size) > msize)
381  {
382  GNUNET_break (0);
384  "Received unexpected message -- exiting\n");
385  goto error;
386  }
387  plugin_name = GNUNET_malloc (plugin_name_size + 1);
388  GNUNET_strlcpy (plugin_name,
389  ((char *) &msg[1]),
390  plugin_name_size + 1);
391 
392  binary = GNUNET_OS_get_libexec_binary_path ("gnunet-cmd");
393 
395  "plugin_name: %s \n",
396  plugin_name);
397 
398  // cmd_binary_process = GNUNET_OS_start_process (
399  /*GNUNET_OS_INHERIT_STD_ERR verbose? ,
400  NULL,
401  NULL,
402  NULL,
403  binary,
404  plugin_name,
405  ni->global_n,
406  ni->local_m,
407  ni->n,
408  ni->m,
409  NULL);*/
410 
411  plugin = GNUNET_new (struct Plugin);
412  plugin->api = GNUNET_PLUGIN_load (plugin_name,
413  NULL);
414  plugin->library_name = GNUNET_strdup (basename(plugin_name));
415 
416  plugin->global_n = ni->global_n;
417  plugin->local_m = ni->local_m;
418  plugin->n = ni->n;
419  plugin->m = ni->m;
420 
421  router_ip = GNUNET_malloc (strlen (ROUTER_BASE_IP) + strlen (plugin->m)
422  + 1);
423  strcpy (router_ip, ROUTER_BASE_IP);
424  strcat (router_ip, plugin->m);
425 
426  node_ip = GNUNET_malloc (strlen (NODE_BASE_IP) + strlen (plugin->n) + 1);
427  strcat (node_ip, NODE_BASE_IP);
428  strcat (node_ip, plugin->n);
429 
430  plugin->api->start_testcase (&write_message, router_ip, node_ip, plugin->m,
431  plugin->n, plugin->local_m);
432 
434  "We got here!\n");
435 
436  /*if (NULL == cmd_binary_process)
437  {
438  LOG (GNUNET_ERROR_TYPE_ERROR,
439  "Starting plugin failed!\n");
440  return GNUNET_SYSERR;
441  }*/
442 
444  "We got here 2!\n");
445 
447  "global_n: %s local_n: %s n: %s m: %s.\n",
448  ni->global_n,
449  ni->local_m,
450  ni->n,
451  ni->m);
452 
454  "We got here 3!\n");
455 
456  GNUNET_free (binary);
457 
458  // done_reading = GNUNET_YES;
459 
460  msg_length = sizeof(struct GNUNET_CMDS_HelperReply);
461  reply = GNUNET_new (struct GNUNET_CMDS_HelperReply);
463  reply->header.size = htons ((uint16_t) msg_length);
464 
466  "We got here 4!\n");
467 
468  write_message ((struct GNUNET_MessageHeader *) reply, msg_length);
469 
471  "We got here 5!\n");
472 
473  /*child_death_task_id = GNUNET_SCHEDULER_add_read_file (
474  GNUNET_TIME_UNIT_FOREVER_REL,
475  GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ),
476  &child_death_task,
477  NULL);*/
478  return GNUNET_OK;
479  }
481  message->type))
482  {
483  plugin->api->all_peers_started ();
484  return GNUNET_OK;
485  }
486  else
487  {
488  LOG (GNUNET_ERROR_TYPE_WARNING, "Received unexpected message -- exiting\n");
489  goto error;
490  }
491 
492 
493  error:
496  "tokenizer shutting down!\n");
498  return GNUNET_SYSERR;
499 }
500 
501 
507 static void
508 read_task (void *cls)
509 {
511  ssize_t sread;
512 
513  read_task_id = NULL;
514  sread = GNUNET_DISK_file_read (stdin_fd, buf, sizeof(buf));
515  if ((GNUNET_SYSERR == sread) || (0 == sread))
516  {
517  LOG_DEBUG ("STDIN closed\n");
519  "tokenizer shutting down during reading!\n");
521  return;
522  }
523  if (GNUNET_YES == done_reading)
524  {
525  /* didn't expect any more data! */
526  GNUNET_break_op (0);
528  "tokenizer shutting down during reading, didn't expect any more data!\n");
530  return;
531  }
532  LOG_DEBUG ("Read %u bytes\n", (unsigned int) sread);
534  "Read %u bytes\n", (unsigned int) sread);
535  /* FIXME: could introduce a GNUNET_MST_read2 to read
536  directly from 'stdin_fd' and save a memcpy() here */
537  if (GNUNET_OK !=
538  GNUNET_MST_from_buffer (tokenizer, buf, sread, GNUNET_NO, GNUNET_NO))
539  {
540  GNUNET_break (0);
542  "tokenizer shutting down during reading, writing to buffer failed!\n");
544  return;
545  }
546  read_task_id /* No timeout while reading */
548  stdin_fd,
549  &read_task,
550  NULL);
551 }
552 
553 
562 static void
563 run (void *cls,
564  char *const *args,
565  const char *cfgfile,
566  const struct GNUNET_CONFIGURATION_Handle *cfg)
567 {
568  struct NodeIdentifier *ni = cls;
569 
570  LOG_DEBUG ("Starting interpreter loop helper...\n");
571 
572  tokenizer = GNUNET_MST_create (&tokenizer_cb, ni);
573  stdin_fd = GNUNET_DISK_get_handle_from_native (stdin);
574  stdout_fd = GNUNET_DISK_get_handle_from_native (stdout);
576  stdin_fd,
577  &read_task,
578  NULL);
580 }
581 
582 
586 static void
588 {
589  static char c;
590  int old_errno; /* back-up errno */
591 
592  old_errno = errno;
593  GNUNET_break (
594  1 ==
597  &c,
598  sizeof(c)));
599  errno = old_errno;
600 }
601 
602 
610 int
611 main (int argc, char **argv)
612 {
613  struct NodeIdentifier *ni;
615  struct GNUNET_GETOPT_CommandLineOption options[] =
617  int ret;
618 
619  GNUNET_log_setup ("gnunet-cmds-helper",
620  "DEBUG",
621  NULL);
622  ni = GNUNET_new (struct NodeIdentifier);
623  ni->global_n = argv[1];
624  ni->local_m = argv[2];
625  ni->n = argv[3];
626  ni->m = argv[4];
627 
629  "global_n: %s local_n: %s n: %s m: %s.\n",
630  ni->global_n,
631  ni->local_m,
632  ni->n,
633  ni->m);
634 
635  status = GNUNET_OK;
636  if (NULL ==
638  {
639  GNUNET_break (0);
640  return 1;
641  }
642  shc_chld =
644  ret = GNUNET_PROGRAM_run (argc,
645  argv,
646  "gnunet-cmds-helper",
647  "Helper for starting a local interpreter loop",
648  options,
649  &run,
650  ni);
652  "run finished\n");
654  shc_chld = NULL;
655  GNUNET_DISK_pipe_close (sigpipe);
656  GNUNET_free (ni);
657  if (GNUNET_OK != ret)
658  return 1;
659  return (GNUNET_OK == status) ? 0 : 1;
660 }
661 
662 
663 /* end of gnunet-cmds-helper.c */
static struct GNUNET_SIGNAL_Context * shc_chld
void * data
The data to write.
No special options, use non-blocking read/write operations.
size_t pos
The current position from where the write operation should begin.
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
static struct GNUNET_SCHEDULER_Task * read_task_id
Task identifier for the read task.
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, parse options).
Definition: program.c:360
#define GNUNET_SIGCHLD
Definition: platform.h:42
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
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, or when GNUNET_SCHEDULER_shutdown() is being invoked.
Definition: scheduler.c:1331
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
char * m
Definition: gnunet-cmd.c:68
enum GNUNET_GenericReturnValue GNUNET_DISK_file_close(struct GNUNET_DISK_FileHandle *h)
Close an open file.
Definition: disk.c:1305
struct GNUNET_BLOCK_PluginFunctions * api
Plugin API.
Definition: block.c:47
const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
static void sighandler_child_death()
Signal handler called for SIGCHLD.
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static int tokenizer_cb(void *cls, const struct GNUNET_MessageHeader *message)
Function to run the test cases.
char * node_ip
Definition: gnunet-cmd.c:58
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_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
static struct GNUNET_SCHEDULER_Task * child_death_task_id
Task to kill the child.
void GNUNET_SIGNAL_handler_uninstall(struct GNUNET_SIGNAL_Context *ctx)
Uninstall a previously installed signal handler.
Definition: signal.c:77
#define GNUNET_new(type)
Allocate a struct or union of the given type.
Definition of a command line option.
#define GNUNET_MESSAGE_TYPE_CMDS_HELPER_REPLY
The reply message from gnunet-cmds-helper.
static struct GNUNET_TESTING_System * test_system
The process handle to the testbed service.
char * library_name
Name of the shared library.
Definition: block.c:42
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format...
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:531
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
static struct GNUNET_SCHEDULER_Task * write_task_id
Task identifier for the write task.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
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:1615
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_OPTION_END
Definition: 002.c:13
Initialization message for gnunet-cmds-testbed to start cmd binary.
static void write_message(struct GNUNET_MessageHeader *message, size_t msg_length)
Task triggered whenever we receive a SIGCHLD (child process died).
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
int main(int argc, char **argv)
Main function.
static struct GNUNET_DISK_FileHandle * stdout_fd
Disk handle for stdout.
void GNUNET_MST_destroy(struct GNUNET_MessageStreamTokenizer *mst)
Destroys a tokenizer.
Definition: mst.c:411
#define LOG_DEBUG(...)
Debug logging shorthand.
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
enum GNUNET_GenericReturnValue GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition: disk.c:1584
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
static struct GNUNET_DISK_PipeHandle * sigpipe
Pipe used to communicate shutdown via signal.
Handle to a message stream tokenizer.
Definition: mst.c:43
static char buf[2048]
struct GNUNET_MessageStreamTokenizer * GNUNET_MST_create(GNUNET_MessageTokenizerCallback cb, void *cb_cls)
Create a message stream tokenizer.
Definition: mst.c:85
#define LOG(kind,...)
Generic logging shortcut.
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
The writing-end of a pipe.
char * global_n
Definition: gnunet-cmd.c:62
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
Reply message from cmds helper process.
#define GNUNET_MESSAGE_TYPE_CMDS_HELPER_INIT
The initialization message towards gnunet-cmds-helper.
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(enum GNUNET_DISK_PipeFlags pf)
Creates an interprocess channel.
Definition: disk.c:1441
void GNUNET_TESTING_system_destroy(struct GNUNET_TESTING_System *system, int remove_paths)
Free system resources.
Definition: testing.c:527
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
Handle for a system on which GNUnet peers are executed; a system is used for reserving unique paths a...
Definition: testing.c:91
struct GNUNET_SCHEDULER_Task * write_task
ID of write task.
#define GNUNET_MAX_MESSAGE_SIZE
Largest supported message (to be precise, one byte more than the largest possible message...
char * plugin_name
Definition: gnunet-cmd.c:60
Interface for functions internally exported from testbed_api.c.
#define ROUTER_BASE_IP
char * n
Definition: gnunet-cmd.c:66
static struct GNUNET_DISK_FileHandle * stdin_fd
Disk handle from stdin.
char * local_m
Definition: gnunet-cmd.c:64
struct GNUNET_MessageStreamTokenizer * tokenizer
Our message stream tokenizer.
configuration data
Handle for a plugin.
Definition: block.c:37
static int status
Result to return in case we fail.
struct GNUNET_SCHEDULER_Task * read_task
Task that reads incoming UDP packets.
Entry in list of pending tasks.
Definition: scheduler.c:134
#define GNUNET_MESSAGE_TYPE_CMDS_HELPER_ALL_PEERS_STARTED
#define NODE_BASE_IP
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 ...
struct Plugin * plugin
Header for all communications.
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
static int done_reading
Are we done reading messages from stdin?
struct GNUNET_DISK_FileHandle * GNUNET_DISK_get_handle_from_native(FILE *fd)
Get a handle from a native FD.
Definition: disk.c:1343
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_CMDS_HELPER_REPLY.
Message formats for communication between testbed api and gnunet-helper-testbed process.
static void shutdown_task(void *cls)
Task to shut down cleanly.
int GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
Setup logging.
size_t length
The length of the data.
size_t GNUNET_strlcpy(char *dst, const char *src, size_t n)
Like strlcpy but portable.
Definition: strings.c:162
Handle used to access files (and pipes).
Handle used to manage a pipe.
Definition: disk.c:68
static void run(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
Main function that will be run.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:972
Context for a single write on a chunk of memory.