GNUnet 0.21.2
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
37#include "platform.h"
38#include "gnunet_util_lib.h"
39#include "gnunet_testing_lib.h"
40#include "testing_api_loop.h"
41#include "testing_cmds.h"
43
47#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
48
52#define LOG_DEBUG(...) LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
53
58{
59
61
63
67 void *data;
68
72 size_t length;
73
77 size_t pos;
78};
79
80
81static struct WriteContext *wc_head;
82
83static struct WriteContext *wc_tail;
84
86
87static const char *my_node_id;
88
93
97static char *plugin_name;
98
103
108
113
118
123
128
132static int global_ret;
133
138static bool finished;
139
140
146static void
147do_shutdown (void *cls)
148{
149 struct WriteContext *wc;
150
151 if (NULL != read_task_id)
152 {
154 read_task_id = NULL;
155 }
156 if (NULL != write_task_id)
157 {
159 write_task_id = NULL;
160 }
161 while (NULL != (wc = wc_head))
162 {
164 wc_tail,
165 wc);
166 GNUNET_free (wc->data);
167 GNUNET_free (wc);
168 }
169 if (NULL != tokenizer)
170 {
172 tokenizer = NULL;
173 }
174 if (NULL != plugin)
175 {
177 plugin);
178 }
179 if (NULL != njt)
180 {
182 njt = NULL;
183 }
184}
185
186
192static void
193write_task (void *cls)
194{
195 struct WriteContext *wc = wc_head;
196 ssize_t bytes_wrote;
197
198 write_task_id = NULL;
199 if (NULL == wc)
200 {
201 if (finished)
203 return;
204 }
205 bytes_wrote
207 wc->data + wc->pos,
208 wc->length - wc->pos);
209 if (GNUNET_SYSERR == bytes_wrote)
210 {
212 "write");
213 GNUNET_free (wc->data);
214 GNUNET_free (wc);
215 global_ret = EXIT_FAILURE;
217 return;
218 }
219 wc->pos += bytes_wrote;
220 if (wc->pos == wc->length)
221 {
223 wc_tail,
224 wc);
225 GNUNET_free (wc->data);
226 GNUNET_free (wc);
227 }
230 stdout_fd,
231 &write_task,
232 NULL);
233}
234
235
240static void
241write_message (const struct GNUNET_MessageHeader *message)
242{
243 struct WriteContext *wc;
244 size_t msg_length = ntohs (message->size);
245
246 wc = GNUNET_new (struct WriteContext);
247 wc->length = msg_length;
248 wc->data = GNUNET_memdup (message,
249 msg_length);
251 wc_tail,
252 wc);
253 if (NULL == write_task_id)
254 {
255 GNUNET_assert (wc_head == wc);
259 stdout_fd,
260 &write_task,
261 NULL);
262 }
263}
264
265
266static void
267finished_cb (void *cls,
269{
272 .header.size = htons (sizeof (reply)),
273 .rv = htonl ((uint32_t) rv)
274 };
275
276 (void) cls;
277 finished = true;
278 write_message (&reply.header);
279}
280
281
284 void *cls,
286{
287 uint16_t msize = ntohs (msg->header.size);
288 uint32_t barrier_count = ntohl (msg->barrier_count);
289 size_t bs = barrier_count * sizeof (struct GNUNET_ShortHashCode);
290 size_t left = msize - bs - sizeof (*msg);
291 const struct GNUNET_ShortHashCode *bd
292 = (const struct GNUNET_ShortHashCode *) &msg[1];
293 const char *topo = (const char *) &bd[barrier_count];
294
295 if (msize < bs + sizeof (*msg))
296 {
297 GNUNET_break_op (0);
298 return GNUNET_SYSERR;
299 }
300 if ('\0' != topo[left - 1])
301 {
302 GNUNET_break_op (0);
303 return GNUNET_SYSERR;
304 }
305 return GNUNET_OK;
306}
307
308
309static void
311 void *cls,
313{
314 uint16_t msize = ntohs (msg->header.size);
315 //uint32_t barrier_count = GNUNET_ntohll (msg->barrier_count);
316 uint32_t barrier_count = ntohl (msg->barrier_count);
317 size_t bs = barrier_count * sizeof (struct GNUNET_ShortHashCode);
318 size_t left = msize - bs - sizeof (*msg);
319 const struct GNUNET_ShortHashCode *bd
320 = (const struct GNUNET_ShortHashCode *) &msg[1];
321 const char *topo = (const char *) &bd[barrier_count];
322
323
324 GNUNET_assert ('\0' == topo[left - 1]);
326 if (NULL == njt)
327 {
328 GNUNET_break_op (0);
329 global_ret = EXIT_FAILURE;
331 return;
332 }
334 my_node_id);
336 (void *) my_node_id);
338 "Starting plugin `%s' for node %s\n",
340 my_node_id);
341 if (NULL == plugin)
342 {
344 "Plugin `%s' not found!\n",
346 global_ret = EXIT_FAILURE;
348 return;
349 }
351 unsigned int i;
352
353 for (i = 0; NULL != commands[i].run; i++)
355 "helper %s\n",
356 commands[i].label.value);
358 topo,
359 barrier_count,
360 bd,
363 NULL);
364}
365
366
367static void
369 void *cls,
371{
372 struct GNUNET_TESTING_Barrier *barrier;
373
374 if (NULL == is)
375 {
376 /* Barrier satisfied *before* helper_init?! */
377 GNUNET_break_op (0);
378 global_ret = EXIT_FAILURE;
380 return;
381 }
383 &cbs->barrier_key);
384 if (barrier->satisfied)
385 {
386 /* Barrier satisfied *twice* is strange... */
387 GNUNET_break_op (0);
388 global_ret = EXIT_FAILURE;
390 return;
391 }
392 barrier->satisfied = true;
394 &cbs->header);
395 for (unsigned int i = 0; i<barrier->cnt_waiting; i++)
397 GNUNET_array_grow (barrier->waiting,
398 barrier->cnt_waiting,
399 0);
400}
401
402
416tokenizer_cb (void *cls,
417 const struct GNUNET_MessageHeader *message)
418{
421 helper_init,
424 NULL),
426 helper_barrier_crossable,
429 NULL),
431 };
432
434 message);
435}
436
437
443static void
445{
446 char buf[GNUNET_MAX_MESSAGE_SIZE];
447 ssize_t sread;
448
449 read_task_id = NULL;
451 buf,
452 sizeof(buf));
453 if (GNUNET_SYSERR == sread)
454 {
455 GNUNET_break (0);
456 global_ret = EXIT_FAILURE;
458 return;
459 }
460 if (0 == sread)
461 {
462 LOG_DEBUG ("STDIN eof\n");
464 return;
465 }
466 if (GNUNET_OK !=
468 buf,
469 sread,
470 GNUNET_NO,
471 GNUNET_NO))
472 {
473 GNUNET_break (0);
474 global_ret = EXIT_FAILURE;
476 return;
477 }
480 stdin_fd,
481 &read_task,
482 NULL);
483}
484
485
494static void
495run (void *cls,
496 char *const *args,
497 const char *cfgfile,
498 const struct GNUNET_CONFIGURATION_Handle *cfg)
499{
500 if (NULL == args[0])
501 {
502 /* must be called with our node ID as 1st argument */
503 GNUNET_break_op (0);
505 return;
506 }
507 my_node_id = args[0];
509 NULL);
513 stdin_fd,
514 &read_task,
515 NULL);
517 NULL);
518}
519
520
528int
529main (int argc,
530 char **argv)
531{
534 };
536
537 ret = GNUNET_PROGRAM_run (argc,
538 argv,
539 "gnunet-cmds-helper",
540 "Helper for starting a local interpreter loop",
541 options,
542 &run,
543 NULL);
544 if (GNUNET_OK != ret)
545 return 1;
546 return global_ret;
547}
548
549
550/* 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_MQ_MessageHandlers handlers[]
Definition: 003.c:1
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
static int ret
Final status code.
Definition: gnunet-arm.c:94
static struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition: gnunet-arm.c:109
static struct GNUNET_MessageStreamTokenizer * tokenizer
Our message stream tokenizer.
static char * plugin_name
Name of our plugin.
static void read_task(void *cls)
Task to read from stdin.
int main(int argc, char **argv)
Main function.
struct GNUNET_TESTING_NetjailTopology * njt
The loaded topology.
static int global_ret
Result to return in case we fail.
static struct WriteContext * wc_tail
static struct GNUNET_DISK_FileHandle * stdout_fd
Disk handle for stdout.
#define LOG_DEBUG(...)
Debug logging shorthand.
static void do_shutdown(void *cls)
Task to shut down cleanly.
static struct GNUNET_TESTING_PluginFunctions * plugin
Plugin to dynamically load a test case.
static void handle_helper_barrier_crossable(void *cls, const struct GNUNET_TESTING_CommandBarrierSatisfied *cbs)
static bool finished
Set to true once we are finished and should exit after sending our final message to the parent.
static struct GNUNET_SCHEDULER_Task * read_task_id
Task identifier for the read task.
static void write_task(void *cls)
Task to write to the standard out.
static struct GNUNET_TESTING_Interpreter * is
static void run(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
Main function that will be run.
static void handle_helper_init(void *cls, const struct GNUNET_TESTING_CommandHelperInit *msg)
static void write_message(const struct GNUNET_MessageHeader *message)
Callback to write a message to the parent process.
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 enum GNUNET_GenericReturnValue check_helper_init(void *cls, const struct GNUNET_TESTING_CommandHelperInit *msg)
static struct WriteContext * wc_head
static const char * my_node_id
static enum GNUNET_GenericReturnValue tokenizer_cb(void *cls, const struct GNUNET_MessageHeader *message)
Functions with this signature are called whenever a complete message is received by the tokenizer.
static void finished_cb(void *cls, enum GNUNET_GenericReturnValue rv)
static struct VoipCommand commands[]
List of supported commands.
void GNUNET_TESTING_async_finish(struct GNUNET_TESTING_AsyncContext *ac)
The asynchronous command of ac has finished.
#define GNUNET_MAX_MESSAGE_SIZE
Largest supported message (to be precise, one byte more than the largest possible message,...
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
struct GNUNET_DISK_FileHandle * GNUNET_DISK_get_handle_from_native(FILE *fd)
Get a handle from a native FD.
Definition: disk.c:1346
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
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert_tail(head, tail, element)
Insert an element at the tail of a DLL.
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
#define GNUNET_log(kind,...)
void * cls
Closure for mv and cb.
GNUNET_GenericReturnValue
Named constants for return values.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
@ GNUNET_OK
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
#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.
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
#define GNUNET_array_grow(arr, size, tsize)
Grow a well-typed (!) array.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
#define GNUNET_memdup(buf, size)
Allocate and initialize a block of memory.
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
enum GNUNET_GenericReturnValue GNUNET_MQ_handle_message(const struct GNUNET_MQ_MessageHandler *handlers, const struct GNUNET_MessageHeader *mh)
Call the message message handler that was registered for the type of the given message in the given h...
Definition: mq.c:205
#define GNUNET_MQ_hd_fixed_size(name, code, str, ctx)
void * GNUNET_PLUGIN_load(const char *library_name, void *arg)
Setup plugin (runs the "init" callback and returns whatever "init" returned).
Definition: plugin.c:198
void * GNUNET_PLUGIN_unload(const char *library_name, void *arg)
Unload plugin (runs the "done" callback and returns whatever "done" returned).
Definition: plugin.c:242
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:400
#define GNUNET_MESSAGE_TYPE_CMDS_HELPER_LOCAL_FINISHED
#define GNUNET_MESSAGE_TYPE_CMDS_HELPER_BARRIER_CROSSABLE
#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:567
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:1695
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:1662
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:1340
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:981
enum GNUNET_GenericReturnValue 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:101
struct GNUNET_MessageStreamTokenizer * GNUNET_MST_create(GNUNET_MessageTokenizerCallback cb, void *cb_cls)
Create a message stream tokenizer.
Definition: mst.c:86
void GNUNET_MST_destroy(struct GNUNET_MessageStreamTokenizer *mst)
Destroys a tokenizer.
Definition: mst.c:404
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
#define EXIT_INVALIDARGUMENT
Definition: platform.h:253
Handle used to access files (and pipes).
Definition of a command line option.
Message handler for a specific message type.
Header for all communications.
Handle to a message stream tokenizer.
Definition: mst.c:45
Entry in list of pending tasks.
Definition: scheduler.c:136
A 256-bit hashcode.
An entry for a barrier list.
struct GNUNET_TESTING_AsyncContext ** waiting
Context of barrier reached commands of our local interpreter that are currently blocked on this barri...
unsigned int cnt_waiting
Length of the waiting array.
bool satisfied
Did we reach expected_reaches? Used in particular if inherited is true and we cannot compute locally.
Parent to child: this barrier was satisfied.
Definition: testing_cmds.h:100
struct GNUNET_MessageHeader header
Definition: testing_cmds.h:101
struct GNUNET_ShortHashCode barrier_key
Definition: testing_cmds.h:102
Initialization message for gnunet-cmds-testbed to start cmd binary.
Definition: testing_cmds.h:42
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_CMDS_HELPER_LOCAL_FINISHED.
Definition: testing_cmds.h:64
uint32_t rv
The exit status local test return with in NBO.
Definition: testing_cmds.h:69
A command to be run by the interpreter.
struct GNUNET_TESTING_CommandLabel 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.
Toplogy of our netjail setup.
The plugin API every test case plugin has to implement.
void * cls
Closure to pass to start_testcase.
struct GNUNET_TESTING_Interpreter *(* start_testcase)(void *cls, const char *topology_data, uint32_t barrier_count, const struct GNUNET_ShortHashCode *barriers, GNUNET_TESTING_cmd_helper_write_cb write_message, GNUNET_TESTING_ResultCallback finish_cb, void *finish_cb_cls)
Function to be implemented for each test case plugin which starts the test case on a netjail node.
Context for a single write on a chunk of memory.
struct WriteContext * prev
void * data
The data to write.
struct WriteContext * next
size_t pos
The current position from where the write operation should begin.
size_t length
The length of the data.
struct GNUNET_TESTING_Barrier * GNUNET_TESTING_get_barrier2_(struct GNUNET_TESTING_Interpreter *is, const struct GNUNET_ShortHashCode *create_key)
void GNUNET_TESTING_loop_notify_children_(struct GNUNET_TESTING_Interpreter *is, const struct GNUNET_MessageHeader *hdr)
Send message to all netjail children (if there are any).
char * GNUNET_TESTING_get_plugin_from_topo(struct GNUNET_TESTING_NetjailTopology *njt, const char *my_node_id)
Get the global plugin name form the topology file.
void GNUNET_TESTING_free_topology(struct GNUNET_TESTING_NetjailTopology *topology)
Deallocate memory of the struct GNUNET_TESTING_NetjailTopology.
struct GNUNET_TESTING_NetjailTopology * GNUNET_TESTING_get_topo_from_string_(const char *input)
Parse the topology data.
Message formats for communication between testing cmds helper and testcase plugins.