GNUnet 0.22.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
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 plugin = NULL;
179 }
180 if (NULL != njt)
181 {
183 njt = NULL;
184 }
185}
186
187
193static void
194do_shutdown (void *cls)
195{
198 NULL);
199}
200
201
207static void
208write_task (void *cls)
209{
210 struct WriteContext *wc = wc_head;
211 ssize_t bytes_wrote;
212
213 write_task_id = NULL;
214 if (NULL == wc)
215 {
216 if (finished)
218 return;
219 }
220 bytes_wrote
222 wc->data + wc->pos,
223 wc->length - wc->pos);
224 if (GNUNET_SYSERR == bytes_wrote)
225 {
227 "write");
228 GNUNET_free (wc->data);
229 GNUNET_free (wc);
230 global_ret = EXIT_FAILURE;
232 return;
233 }
234 wc->pos += bytes_wrote;
235 if (wc->pos == wc->length)
236 {
238 wc_tail,
239 wc);
240 GNUNET_free (wc->data);
241 GNUNET_free (wc);
242 }
245 stdout_fd,
246 &write_task,
247 NULL);
248}
249
250
255static void
256write_message (const struct GNUNET_MessageHeader *message)
257{
258 struct WriteContext *wc;
259 size_t msg_length = ntohs (message->size);
260
261 wc = GNUNET_new (struct WriteContext);
262 wc->length = msg_length;
263 wc->data = GNUNET_memdup (message,
264 msg_length);
266 wc_tail,
267 wc);
268 if (NULL == write_task_id)
269 {
270 GNUNET_assert (wc_head == wc);
274 stdout_fd,
275 &write_task,
276 NULL);
277 }
278}
279
280
281static void
282finished_cb (void *cls,
284{
287 .header.size = htons (sizeof (reply)),
288 .rv = htonl ((uint32_t) rv)
289 };
290
291 (void) cls;
292 finished = true;
293 write_message (&reply.header);
294}
295
296
299 void *cls,
301{
302 uint16_t msize = ntohs (msg->header.size);
303 uint32_t barrier_count = ntohl (msg->barrier_count);
304 size_t bs = barrier_count * sizeof (struct GNUNET_ShortHashCode);
305 size_t left = msize - bs - sizeof (*msg);
306 const struct GNUNET_ShortHashCode *bd
307 = (const struct GNUNET_ShortHashCode *) &msg[1];
308 const char *topo = (const char *) &bd[barrier_count];
309
310 if (msize < bs + sizeof (*msg))
311 {
312 GNUNET_break_op (0);
313 return GNUNET_SYSERR;
314 }
315 if ('\0' != topo[left - 1])
316 {
317 GNUNET_break_op (0);
318 return GNUNET_SYSERR;
319 }
320 return GNUNET_OK;
321}
322
323
324static void
326 void *cls,
328{
329 uint16_t msize = ntohs (msg->header.size);
330 // uint32_t barrier_count = GNUNET_ntohll (msg->barrier_count);
331 uint32_t barrier_count = ntohl (msg->barrier_count);
332 size_t bs = barrier_count * sizeof (struct GNUNET_ShortHashCode);
333 size_t left = msize - bs - sizeof (*msg);
334 const struct GNUNET_ShortHashCode *bd
335 = (const struct GNUNET_ShortHashCode *) &msg[1];
336 const char *topo = (const char *) &bd[barrier_count];
337 const struct GNUNET_OS_ProjectData *pd
339
340 if (NULL != plugin)
341 {
343 "Double-init!\n");
344 global_ret = EXIT_FAILURE;
346 return;
347 }
348
349 GNUNET_assert ('\0' == topo[left - 1]);
351 if (NULL == njt)
352 {
353 GNUNET_break_op (0);
354 global_ret = EXIT_FAILURE;
356 return;
357 }
359 my_node_id);
362 (void *) my_node_id);
364 "Starting plugin `%s' for node %s\n",
366 my_node_id);
367 if (NULL == plugin)
368 {
370 "Plugin `%s' not found!\n",
372 global_ret = EXIT_FAILURE;
374 return;
375 }
376 {
378
379 for (unsigned int i = 0; NULL != commands[i].run; i++)
381 "helper %s\n",
382 commands[i].label.value);
383 }
385 topo,
386 barrier_count,
387 bd,
390 NULL);
391}
392
393
394static void
396 void *cls,
398{
399 struct GNUNET_TESTING_Barrier *barrier;
400
401 if (NULL == is)
402 {
403 /* Barrier satisfied *before* helper_init?! */
404 GNUNET_break_op (0);
405 global_ret = EXIT_FAILURE;
407 return;
408 }
410 &cbs->barrier_key);
411 if (barrier->satisfied)
412 {
413 /* Barrier satisfied *twice* is strange... */
414 GNUNET_break_op (0);
415 global_ret = EXIT_FAILURE;
417 return;
418 }
419 barrier->satisfied = true;
421 &cbs->header);
422 for (unsigned int i = 0; i<barrier->cnt_waiting; i++)
424 GNUNET_array_grow (barrier->waiting,
425 barrier->cnt_waiting,
426 0);
427}
428
429
443tokenizer_cb (void *cls,
444 const struct GNUNET_MessageHeader *message)
445{
448 helper_init,
451 NULL),
453 helper_barrier_crossable,
456 NULL),
458 };
459
461 message);
462}
463
464
470static void
472{
473 char buf[GNUNET_MAX_MESSAGE_SIZE];
474 ssize_t sread;
475
476 read_task_id = NULL;
478 buf,
479 sizeof(buf));
480 if (GNUNET_SYSERR == sread)
481 {
482 GNUNET_break (0);
483 global_ret = EXIT_FAILURE;
485 return;
486 }
487 if (0 == sread)
488 {
489 LOG_DEBUG ("STDIN eof\n");
491 return;
492 }
493 if (GNUNET_OK !=
495 buf,
496 sread,
497 GNUNET_NO,
498 GNUNET_NO))
499 {
500 GNUNET_break (0);
501 global_ret = EXIT_FAILURE;
503 return;
504 }
507 stdin_fd,
508 &read_task,
509 NULL);
510}
511
512
521static void
522run (void *cls,
523 char *const *args,
524 const char *cfgfile,
525 const struct GNUNET_CONFIGURATION_Handle *cfg)
526{
527 if (NULL == args[0])
528 {
529 /* must be called with our node ID as 1st argument */
530 GNUNET_break_op (0);
532 return;
533 }
534 my_node_id = args[0];
536 NULL);
540 stdin_fd,
541 &read_task,
542 NULL);
544 NULL);
545}
546
547
555int
556main (int argc,
557 char **argv)
558{
561 };
563 const struct GNUNET_OS_ProjectData *pd
565
567 argc,
568 argv,
569 "gnunet-cmds-helper",
570 "Helper for starting a local interpreter loop",
571 options,
572 &run,
573 NULL);
574 if (GNUNET_OK != ret)
575 return 1;
576 return global_ret;
577}
578
579
580/* 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:93
static struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition: gnunet-arm.c:108
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 void do_shutdown_later(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:697
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:660
#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_SCHEDULER_PRIORITY_IDLE
Run when otherwise idle.
@ 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)
const struct GNUNET_OS_ProjectData * GNUNET_OS_project_data_gnunet(void)
Return default project data used by 'libgnunetutil' for GNUnet.
void * GNUNET_PLUGIN_load(const struct GNUNET_OS_ProjectData *pd, const char *library_name, void *arg)
Setup plugin (runs the "init" callback and returns whatever "init" returned).
Definition: plugin.c:221
void * GNUNET_PLUGIN_unload(const char *library_name, void *arg)
Unload plugin (runs the "done" callback and returns whatever "done" returned).
Definition: plugin.c:277
enum GNUNET_GenericReturnValue GNUNET_PROGRAM_run(const struct GNUNET_OS_ProjectData *pd, 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:407
#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:1694
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:1661
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:1339
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:980
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_with_priority(enum GNUNET_SCHEDULER_Priority prio, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified priority.
Definition: scheduler.c:1231
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:254
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
Project-specific data used to help the OS subsystem find installation paths.
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.