GNUnet 0.24.1-15-gab6ed22f1
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);
179 plugin = NULL;
180 }
181 if (NULL != njt)
182 {
184 njt = NULL;
185 }
186}
187
188
194static void
195do_shutdown (void *cls)
196{
199 NULL);
200}
201
202
208static void
209write_task (void *cls)
210{
211 struct WriteContext *wc = wc_head;
212 ssize_t bytes_wrote;
213
214 write_task_id = NULL;
215 if (NULL == wc)
216 {
217 if (finished)
219 return;
220 }
221 bytes_wrote
223 wc->data + wc->pos,
224 wc->length - wc->pos);
225 if (GNUNET_SYSERR == bytes_wrote)
226 {
228 "write");
229 GNUNET_free (wc->data);
230 GNUNET_free (wc);
231 global_ret = EXIT_FAILURE;
233 return;
234 }
235 wc->pos += bytes_wrote;
236 if (wc->pos == wc->length)
237 {
239 wc_tail,
240 wc);
241 GNUNET_free (wc->data);
242 GNUNET_free (wc);
243 }
246 stdout_fd,
247 &write_task,
248 NULL);
249}
250
251
256static void
257write_message (const struct GNUNET_MessageHeader *message)
258{
259 struct WriteContext *wc;
260 size_t msg_length = ntohs (message->size);
261
262 wc = GNUNET_new (struct WriteContext);
263 wc->length = msg_length;
264 wc->data = GNUNET_memdup (message,
265 msg_length);
267 wc_tail,
268 wc);
269 if (NULL == write_task_id)
270 {
271 GNUNET_assert (wc_head == wc);
275 stdout_fd,
276 &write_task,
277 NULL);
278 }
279}
280
281
282static void
283finished_cb (void *cls,
285{
288 .header.size = htons (sizeof (reply)),
289 .rv = htonl ((uint32_t) rv)
290 };
291
292 (void) cls;
293 finished = true;
294 write_message (&reply.header);
295}
296
297
300 void *cls,
302{
303 uint16_t msize = ntohs (msg->header.size);
304 uint32_t barrier_count = ntohl (msg->barrier_count);
305 size_t bs = barrier_count * sizeof (struct GNUNET_ShortHashCode);
306 size_t left = msize - bs - sizeof (*msg);
307 const struct GNUNET_ShortHashCode *bd
308 = (const struct GNUNET_ShortHashCode *) &msg[1];
309 const char *topo = (const char *) &bd[barrier_count];
310
311 if (msize < bs + sizeof (*msg))
312 {
313 GNUNET_break_op (0);
314 return GNUNET_SYSERR;
315 }
316 if ('\0' != topo[left - 1])
317 {
318 GNUNET_break_op (0);
319 return GNUNET_SYSERR;
320 }
321 return GNUNET_OK;
322}
323
324
325static void
327 void *cls,
329{
330 uint16_t msize = ntohs (msg->header.size);
331 // uint32_t barrier_count = GNUNET_ntohll (msg->barrier_count);
332 uint32_t barrier_count = ntohl (msg->barrier_count);
333 size_t bs = barrier_count * sizeof (struct GNUNET_ShortHashCode);
334 size_t left = msize - bs - sizeof (*msg);
335 const struct GNUNET_ShortHashCode *bd
336 = (const struct GNUNET_ShortHashCode *) &msg[1];
337 const char *topo = (const char *) &bd[barrier_count];
338 const struct GNUNET_OS_ProjectData *pd
340
341 if (NULL != plugin)
342 {
344 "Double-init!\n");
345 global_ret = EXIT_FAILURE;
347 return;
348 }
349
350 GNUNET_assert ('\0' == topo[left - 1]);
352 if (NULL == njt)
353 {
354 GNUNET_break_op (0);
355 global_ret = EXIT_FAILURE;
357 return;
358 }
359 GNUNET_asprintf (&plugin_name, "libgnunet_plugin_testing_%s",
361 my_node_id));
364 (void *) my_node_id);
366 "Starting plugin `%s' for node %s\n",
368 my_node_id);
369 if (NULL == plugin)
370 {
372 "Plugin `%s' not found!\n",
374 global_ret = EXIT_FAILURE;
376 return;
377 }
378 {
380
381 for (unsigned int i = 0; NULL != commands[i].run; i++)
383 "helper %s\n",
384 commands[i].label.value);
385 }
387 topo,
388 barrier_count,
389 bd,
392 NULL);
393}
394
395
396static void
398 void *cls,
400{
401 struct GNUNET_TESTING_Barrier *barrier;
402
403 if (NULL == is)
404 {
405 /* Barrier satisfied *before* helper_init?! */
406 GNUNET_break_op (0);
407 global_ret = EXIT_FAILURE;
409 return;
410 }
412 &cbs->barrier_key);
413 if (barrier->satisfied)
414 {
415 /* Barrier satisfied *twice* is strange... */
416 GNUNET_break_op (0);
417 global_ret = EXIT_FAILURE;
419 return;
420 }
421 barrier->satisfied = true;
423 &cbs->header);
424 for (unsigned int i = 0; i<barrier->cnt_waiting; i++)
426 GNUNET_array_grow (barrier->waiting,
427 barrier->cnt_waiting,
428 0);
429}
430
431
445tokenizer_cb (void *cls,
446 const struct GNUNET_MessageHeader *message)
447{
450 helper_init,
453 NULL),
455 helper_barrier_crossable,
458 NULL),
460 };
461
463 message);
464}
465
466
472static void
474{
475 char buf[GNUNET_MAX_MESSAGE_SIZE];
476 ssize_t sread;
477
478 read_task_id = NULL;
480 buf,
481 sizeof(buf));
482 if (GNUNET_SYSERR == sread)
483 {
484 GNUNET_break (0);
485 global_ret = EXIT_FAILURE;
487 return;
488 }
489 if (0 == sread)
490 {
491 LOG_DEBUG ("STDIN eof\n");
493 return;
494 }
495 if (GNUNET_OK !=
497 buf,
498 sread,
499 GNUNET_NO,
500 GNUNET_NO))
501 {
502 GNUNET_break (0);
503 global_ret = EXIT_FAILURE;
505 return;
506 }
509 stdin_fd,
510 &read_task,
511 NULL);
512}
513
514
523static void
524run (void *cls,
525 char *const *args,
526 const char *cfgfile,
527 const struct GNUNET_CONFIGURATION_Handle *cfg)
528{
529 if (NULL == args[0])
530 {
531 /* must be called with our node ID as 1st argument */
532 GNUNET_break_op (0);
534 return;
535 }
536 my_node_id = args[0];
538 NULL);
542 stdin_fd,
543 &read_task,
544 NULL);
546 NULL);
547}
548
549
557int
558main (int argc,
559 char **argv)
560{
563 };
565 const struct GNUNET_OS_ProjectData *pd
567
569 argc,
570 argv,
571 "gnunet-cmds-helper",
572 "Helper for starting a local interpreter loop",
573 options,
574 &run,
575 NULL);
576 if (GNUNET_OK != ret)
577 return 1;
578 return global_ret;
579}
580
581
582/* 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:700
struct GNUNET_DISK_FileHandle * GNUNET_DISK_get_handle_from_native(FILE *fd)
Get a handle from a native FD.
Definition: disk.c:1360
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:663
#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
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#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.
Topology 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).
const 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.