GNUnet 0.21.2
testing_api_cmd_netjail_start_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 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_testing_lib.h"
28#include "testing_api_barrier.h"
29#include "testing_api_loop.h"
30#include "testing_cmds.h"
32
33
37#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
38
39
45
46
50struct NetJailState
51{
57
62
66 const char *topology_cmd_label;
67
72
77
82
87
92
96 const char *topology_data;
97
101 unsigned int n_helpers;
102
106 unsigned int n_finished;
107
111 bool failed;
112};
113
119{
120
125
130
135
140
141
142};
143
144
153static void
154clear_msg (void *cls,
156{
157 struct TestingSystemCount *tbc = cls;
158 struct NetJailState *ns = tbc->ns;
159
160 GNUNET_assert (NULL != tbc->shandle);
161 tbc->shandle = NULL;
163 ns->tbc_tail,
164 tbc);
165 GNUNET_free (tbc);
166 if ( (! ns->failed) &&
167 (GNUNET_OK != result) )
168 {
169 ns->failed = true;
171 }
172}
173
174
175static void
177 void *cls,
179{
180 struct NetJailState *ns = cls;
181 struct GNUNET_TESTING_Barrier *barrier;
182
183 barrier = GNUNET_TESTING_get_barrier2_ (ns->is,
184 &rm->barrier_key);
185 if (NULL == barrier)
186 {
187 if (! ns->failed)
188 {
189 ns->failed = true;
191 }
192 return;
193 }
194 if (barrier->inherited)
195 {
196 /* pass on to parent */
198 &rm->header);
199 }
200 else
201 {
202 barrier->reached++;
203 if (barrier->reached == barrier->expected_reaches)
204 {
206 .header.size
207 = htons (sizeof (cbs)),
208 .header.type
210 .barrier_key
211 = rm->barrier_key
212 };
213
214 GNUNET_assert (! barrier->satisfied);
215 barrier->satisfied = true;
216 /* unblock children */
218 &cbs.header);
219 /* unblock self */
220 for (unsigned int i = 0; i<barrier->cnt_waiting; i++)
222 GNUNET_array_grow (barrier->waiting,
223 barrier->cnt_waiting,
224 0);
225 }
226 }
227}
228
229
230static void
232 void *cls,
234{
235 struct NetJailState *ns = cls;
236
237 ns->n_finished++;
238 if ( (! ns->failed) &&
239 (GNUNET_OK != ntohl (lf->rv)) )
240 {
241 ns->failed = true;
243 return;
244 }
245 if (ns->n_finished == ns->n_helpers)
246 {
247 GNUNET_SCHEDULER_cancel (ns->timeout_task);
248 ns->timeout_task = NULL;
250 }
251}
252
253
265helper_mst (void *cls,
266 const struct GNUNET_MessageHeader *message)
267{
268 struct NetJailState *ns = cls;
271 helper_barrier_reached,
274 ns),
276 helper_local_finished,
279 ns),
281 };
283
285 message);
286 if (GNUNET_OK != ret)
287 {
288 GNUNET_break (0);
289 if (! ns->failed)
290 {
291 ns->failed = true;
293 }
294 }
295 return ret;
296}
297
298
302static void
303exp_cb (void *cls)
304{
305 struct NetJailState *ns = cls;
306
308 "Called exp_cb.\n");
309 if (NULL != ns->timeout_task)
310 {
311 GNUNET_SCHEDULER_cancel (ns->timeout_task);
312 ns->timeout_task = NULL;
313 }
314 if (! ns->failed)
316}
317
318
320add_barrier (void *cls,
321 const struct GNUNET_ShortHashCode *key,
322 void *value)
323{
324 struct GNUNET_ShortHashCode **bar_posp = cls;
325 struct GNUNET_ShortHashCode *bar_pos = *bar_posp;
326
327 *bar_pos = *key;
328 *bar_posp = bar_pos + 1;
329 return GNUNET_OK;
330}
331
332
336static bool
338 struct GNUNET_HELPER_Handle *helper)
339{
341 struct TestingSystemCount *tbc;
342 struct GNUNET_ShortHashCode *bar;
343 struct GNUNET_ShortHashCode *bar_pos;
344 unsigned int num_barriers = GNUNET_TESTING_barrier_count_ (ns->is);
345 size_t topo_length;
346 size_t msg_len;
347
348 topo_length = strlen (ns->topology_data) + 1;
349 GNUNET_assert (topo_length < SIZE_MAX - sizeof (*msg));
350 GNUNET_assert (SIZE_MAX / sizeof (struct GNUNET_ShortHashCode) >
351 num_barriers);
352 GNUNET_assert (sizeof (*msg) + topo_length <
354 - num_barriers * sizeof (struct GNUNET_ShortHashCode));
355 msg_len = sizeof (*msg) + topo_length
356 + num_barriers * sizeof (struct GNUNET_ShortHashCode);
357 if (msg_len > UINT16_MAX)
358 {
359 /* ask a wizard to enhance the protocol;
360 start with gzip topology_data? multiple
361 init messages for barriers + topo data,
362 etc.*/
363 GNUNET_break (0);
364 return false;
365 }
366 msg = GNUNET_malloc (msg_len);
367 msg->header.size = htons ((uint16_t) msg_len);
369 msg->barrier_count = htonl (num_barriers);
370 bar = (struct GNUNET_ShortHashCode *) &msg[1];
371 bar_pos = bar;
374 &bar_pos);
375 GNUNET_assert (bar_pos == &bar[num_barriers]);
376 memcpy (&bar[num_barriers],
377 ns->topology_data,
378 topo_length);
379 tbc = GNUNET_new (struct TestingSystemCount);
380 tbc->ns = ns;
382 helper,
383 &msg->header,
384 GNUNET_NO,
385 &clear_msg,
386 tbc);
388 if (NULL == tbc->shandle)
389 {
391 "Send handle is NULL!\n");
392 GNUNET_free (tbc);
393 return false;
394 }
396 ns->tbc_tail,
397 tbc);
398 return true;
399}
400
401
406static bool
408 unsigned int script_num)
409{
410 char *gnunet_cmds_helper
412 char node_id[32];
413 char *data_dir;
414 char *script_name;
415 struct GNUNET_HELPER_Handle *helper;
416
418 GNUNET_asprintf (&script_name,
419 "%s%s",
420 data_dir,
422 GNUNET_snprintf (node_id,
423 sizeof (node_id),
424 "if%06x-%06x\n",
425 (unsigned int) getpid (),
426 script_num);
427 {
428 char *const script_argv[] = {
429 script_name,
430 node_id,
431 gnunet_cmds_helper,
432 node_id,
433 NULL
434 };
435 helper = GNUNET_HELPER_start (
436 GNUNET_YES, /* with control pipe */
437 script_argv[0],
438 script_argv,
439 &helper_mst,
440 &exp_cb,
441 ns);
442 }
443 GNUNET_free (gnunet_cmds_helper);
444 if (NULL == helper)
445 {
446 GNUNET_break (0);
447 return false;
448 }
449 GNUNET_array_append (ns->helpers,
450 ns->n_helpers,
451 helper);
453 helper);
454 GNUNET_free (data_dir);
455 GNUNET_free (script_name);
456 return send_start_messages (ns,
457 helper);
458}
459
460
466static void
467do_timeout (void *cls)
468{
469 struct NetJailState *ns = cls;
470
471 ns->timeout_task = NULL;
473 "Terminating cmd due to global timeout\n");
475}
476
477
485static void
488{
489 struct NetJailState *ns = cls;
490 struct GNUNET_TESTING_NetjailTopology *topology;
491 bool failed = false;
492 const struct GNUNET_TESTING_Command *topo_cmd;
493
494 ns->is = is;
496 ns->topology_cmd_label);
497 if (NULL == topo_cmd)
499 if (GNUNET_OK !=
500 GNUNET_TESTING_get_trait_topology_string (topo_cmd,
501 &ns->topology_data))
503 topology
504 = GNUNET_TESTING_get_topo_from_string_ (ns->topology_data);
505 for (unsigned int i = 1; i <= topology->total; i++)
506 {
507 if (! start_helper (ns,
508 i))
509 {
510 failed = true;
511 break;
512 }
513 }
515 if (failed)
516 {
517 ns->failed = true;
519 }
520 ns->timeout_task
522 &do_timeout,
523 ns);
524}
525
526
532static void
534{
535 struct NetJailState *ns = cls;
536
537 if (NULL != ns->timeout_task)
538 {
539 GNUNET_SCHEDULER_cancel (ns->timeout_task);
540 ns->timeout_task = NULL;
541 }
542 for (unsigned int i = 0; i<ns->n_helpers; i++)
543 GNUNET_HELPER_stop (ns->helpers[i],
544 GNUNET_YES);
545 GNUNET_free (ns);
546}
547
548
554 const void **ret,
555 const char *trait,
556 unsigned int index)
557{
558 struct NetJailState *ns = cls;
559 struct GNUNET_TESTING_Trait traits[] = {
561 };
562
563 (void) ns;
565 ret,
566 trait,
567 index);
568}
569
570
581 const char *label,
582 const char *topology_cmd_label,
584{
585 struct NetJailState *ns;
586
587 ns = GNUNET_new (struct NetJailState);
588 ns->topology_cmd_label = topology_cmd_label;
589 ns->timeout = timeout;
591 label,
595 &ns->ac);
596}
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_TIME_Relative timeout
User defined timestamp for completing operations.
Definition: gnunet-arm.c:119
static struct GNUNET_TESTING_Interpreter * is
struct GNUNET_HashCode key
The key used in the DHT.
static struct GNUNET_NAMECACHE_Handle * ns
Handle to the namecache.
static char * value
Value of the record to add/remove.
static int result
Global testing status.
void lf(char *msg)
Definition: gnunet_gst.c:587
struct GNUNET_TESTING_Command GNUNET_TESTING_command_new_ac(void *cls, const char *label, GNUNET_TESTING_CommandRunRoutine run, GNUNET_TESTING_CommandCleanupRoutine cleanup, GNUNET_TESTING_CommandGetTraits traits, struct GNUNET_TESTING_AsyncContext *ac)
Create a new command that may be asynchronous.
void GNUNET_TESTING_async_finish(struct GNUNET_TESTING_AsyncContext *ac)
The asynchronous command of ac has finished.
#define GNUNET_TESTING_FAIL(is)
Print failing line number and trigger shutdown.
void GNUNET_TESTING_async_fail(struct GNUNET_TESTING_AsyncContext *ac)
The asynchronous command of ac has failed.
const struct GNUNET_TESTING_Command * GNUNET_TESTING_interpreter_lookup_command(struct GNUNET_TESTING_Interpreter *is, const char *label)
Lookup command by label.
struct GNUNET_TESTING_Trait GNUNET_TESTING_trait_end(void)
"end" of traits array.
enum GNUNET_GenericReturnValue GNUNET_TESTING_get_trait(const struct GNUNET_TESTING_Trait *traits, const void **ret, const char *trait, unsigned int index)
Obtain value of a trait from a command.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
struct GNUNET_HELPER_SendHandle * GNUNET_HELPER_send(struct GNUNET_HELPER_Handle *h, const struct GNUNET_MessageHeader *msg, bool can_drop, GNUNET_HELPER_Continuation cont, void *cont_cls)
Send an message to the helper.
Definition: helper.c:613
struct GNUNET_HELPER_Handle * GNUNET_HELPER_start(int with_control_pipe, const char *binary_name, char *const binary_argv[], GNUNET_MessageTokenizerCallback cb, GNUNET_HELPER_ExceptionCallback exp_cb, void *cb_cls)
Starts a helper and begins reading from it.
Definition: helper.c:460
void GNUNET_HELPER_stop(struct GNUNET_HELPER_Handle *h, int soft_kill)
Kills the helper, closes the pipe, frees the handle and calls wait() on the helper process.
Definition: helper.c:536
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_YES
@ GNUNET_NO
#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_ERROR
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.
int GNUNET_snprintf(char *buf, size_t size, const char *format,...) __attribute__((format(printf
Like snprintf, just aborts if the buffer is of insufficient size.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_array_append(arr, len, element)
Append an element to an array (growing the array by one).
#define GNUNET_free(ptr)
Wrapper around free.
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
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)
char * GNUNET_OS_installation_get_path(enum GNUNET_OS_InstallationPathKind dirkind)
Get the path to a specific GNUnet installation directory or, with GNUNET_OS_IPK_SELF_PREFIX,...
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 ...
@ GNUNET_OS_IPK_DATADIR
Return the directory where data is installed (share/gnunet/)
#define GNUNET_MESSAGE_TYPE_CMDS_HELPER_LOCAL_FINISHED
#define GNUNET_MESSAGE_TYPE_CMDS_HELPER_BARRIER_REACHED
#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_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:981
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1278
#define SIZE_MAX
Definition: platform.h:208
The handle to a helper process.
Definition: helper.c:77
Entry in the queue of messages we need to transmit to the helper.
Definition: helper.c:35
Message handler for a specific message type.
Header for all communications.
Entry in list of pending tasks.
Definition: scheduler.c:136
A 256-bit hashcode.
State each asynchronous command must have in its closure.
An entry for a barrier list.
bool inherited
Did we inherit the barrier from our parent loop?
unsigned int reached
Number of times the barrier has been reached.
unsigned int expected_reaches
Number of total commands expected to be reached by the barrier.
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.
Child to parent: I reached the given barrier, increment the counter (or pass to grandparent).
Definition: testing_cmds.h:78
struct GNUNET_ShortHashCode barrier_key
Definition: testing_cmds.h:80
struct GNUNET_MessageHeader header
Definition: testing_cmds.h:79
Parent to child: this barrier was satisfied.
Definition: testing_cmds.h:100
struct GNUNET_MessageHeader header
Definition: testing_cmds.h:101
Initialization message for gnunet-cmds-testbed to start cmd binary.
Definition: testing_cmds.h:42
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.
unsigned int total
Total number of namespaces in the topology.
A struct GNUNET_TESTING_Trait can be used to exchange data between cmds.
unsigned int index
Index number associated with the trait.
Time for relative time used by GNUnet, in microseconds.
Struct to hold information for callbacks.
struct GNUNET_HELPER_Handle ** helpers
Array with handles of helper processes.
struct TestingSystemCount * tbc_tail
Kept in a DLL.
const char * topology_data
Data about our topology as a string.
struct GNUNET_TESTING_Interpreter * is
Global state of the interpreter, used by a command to access information about other commands.
const char * topology_cmd_label
Configuration file for the test topology.
struct TestingSystemCount * tbc_head
Kept in a DLL.
unsigned int n_finished
Counts number of helpers that finished.
bool failed
Set to true if we already failed the command.
unsigned int n_helpers
Size of the array helpers.
struct GNUNET_TESTING_AsyncContext ac
Context for our asynchronous completion.
struct GNUNET_TIME_Relative timeout
Time after this cmd has to finish.
struct GNUNET_SCHEDULER_Task * timeout_task
Timeout task.
Struct containing the number of the netjail node and the NetJailState which will be handed to callbac...
struct GNUNET_HELPER_SendHandle * shandle
The send handle for the helper.
struct TestingSystemCount * next
Kept in a DLL.
struct TestingSystemCount * prev
Kept in a DLL.
struct NetJailState * ns
Struct to store information handed over to callbacks.
static enum GNUNET_GenericReturnValue traits(void *cls, const void **ret, const char *trait, unsigned int index)
This function prepares an array with traits.
static bool start_helper(struct NetJailState *ns, unsigned int script_num)
Function which start a single helper process.
struct GNUNET_TESTING_Command GNUNET_TESTING_cmd_netjail_start_helpers(const char *label, const char *topology_cmd_label, struct GNUNET_TIME_Relative timeout)
Create command.
static enum GNUNET_GenericReturnValue helper_mst(void *cls, const struct GNUNET_MessageHeader *message)
Functions with this signature are called whenever a complete message is received by the tokenizer.
static void exp_cb(void *cls)
Callback called if there was an exception during execution of the helper.
static void do_timeout(void *cls)
Function run when the cmd terminates (good or bad) with timeout.
static enum GNUNET_GenericReturnValue add_barrier(void *cls, const struct GNUNET_ShortHashCode *key, void *value)
static void netjail_exec_cleanup(void *cls)
Code to clean up resource this cmd used.
static void netjail_exec_run(void *cls, struct GNUNET_TESTING_Interpreter *is)
This function starts a helper process for each node.
static enum GNUNET_GenericReturnValue netjail_exec_traits(void *cls, const void **ret, const char *trait, unsigned int index)
This function prepares an array with traits.
static void handle_helper_barrier_reached(void *cls, const struct GNUNET_TESTING_CommandBarrierReached *rm)
static bool send_start_messages(struct NetJailState *ns, struct GNUNET_HELPER_Handle *helper)
static void handle_helper_local_finished(void *cls, const struct GNUNET_TESTING_CommandLocalFinished *lf)
static void clear_msg(void *cls, enum GNUNET_GenericReturnValue result)
Continuation function from GNUNET_HELPER_send()
struct GNUNET_TESTING_Barrier * GNUNET_TESTING_get_barrier2_(struct GNUNET_TESTING_Interpreter *is, const struct GNUNET_ShortHashCode *create_key)
unsigned int GNUNET_TESTING_barrier_count_(struct GNUNET_TESTING_Interpreter *is)
void GNUNET_TESTING_barrier_iterate_(struct GNUNET_TESTING_Interpreter *is, GNUNET_CONTAINER_ShortmapIterator cb, void *cb_cls)
void GNUNET_TESTING_add_netjail_helper_(struct GNUNET_TESTING_Interpreter *is, struct GNUNET_HELPER_Handle *helper)
Adding a helper handle to the interpreter.
void GNUNET_TESTING_loop_notify_parent_(struct GNUNET_TESTING_Interpreter *is, const struct GNUNET_MessageHeader *hdr)
Send message to our parent.
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).
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.
#define HELPER_CMDS_BINARY
Definition: testing_cmds.h:32
#define NETJAIL_EXEC_SCRIPT
Definition: testing_cmds.h:34