From 34e1c58cb39a649c9a4c551681cedf19807b85f0 Mon Sep 17 00:00:00 2001 From: t3sserakt Date: Wed, 7 Dec 2022 12:42:31 +0100 Subject: - added configuration to be able to start executables on a router node - added barrier functionality --- src/testing/Makefile.am | 2 + src/testing/gnunet-cmds-helper.c | 81 ++----- src/testing/netjail_core.sh | 260 --------------------- src/testing/netjail_exec.sh | 14 -- src/testing/netjail_start.sh | 74 ------ src/testing/netjail_stop.sh | 59 ----- src/testing/testing.c | 25 +- src/testing/testing_api_cmd_barrier.c | 256 ++++++++++++++++++++ src/testing/testing_api_cmd_barrier_reached.c | 214 +++++++++++++++++ .../testing_api_cmd_block_until_external_trigger.c | 2 - src/testing/testing_api_cmd_local_test_prepared.c | 6 +- .../testing_api_cmd_netjail_start_testsystem.c | 248 +++++++++++++------- .../testing_api_cmd_netjail_stop_testsystem.c | 2 +- src/testing/testing_api_cmd_send_peer_ready.c | 8 +- src/testing/testing_api_loop.c | 250 +++++++++++++++++++- src/testing/testing_cmds.h | 64 ++++- 16 files changed, 998 insertions(+), 567 deletions(-) delete mode 100755 src/testing/netjail_core.sh delete mode 100755 src/testing/netjail_exec.sh delete mode 100755 src/testing/netjail_start.sh delete mode 100755 src/testing/netjail_stop.sh create mode 100644 src/testing/testing_api_cmd_barrier.c create mode 100644 src/testing/testing_api_cmd_barrier_reached.c (limited to 'src/testing') diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am index bcb45da70..3a4990db4 100644 --- a/src/testing/Makefile.am +++ b/src/testing/Makefile.am @@ -29,6 +29,8 @@ gnunet_cmds_helper_LDADD = $(XLIB) \ $(LTLIBINTL) $(Z_LIBS) libgnunettesting_la_SOURCES = \ + testing_api_cmd_barrier.c \ + testing_api_cmd_barrier_reached.c \ testing_api_cmd_end.c \ testing_api_cmd_finish.c \ testing_api_cmd_local_test_finished.c \ diff --git a/src/testing/gnunet-cmds-helper.c b/src/testing/gnunet-cmds-helper.c index 8114d156d..477c8c60f 100644 --- a/src/testing/gnunet-cmds-helper.c +++ b/src/testing/gnunet-cmds-helper.c @@ -43,12 +43,13 @@ #include "gnunet_testing_netjail_lib.h" #include "testing_cmds.h" #include "gnunet_testing_plugin.h" +#include "gnunet_testing_barrier.h" #include /** * Generic logging shortcut -testing_api_cmd_block_until_all_peers_started.c */ + */ #define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__) /** @@ -64,58 +65,6 @@ testing_api_cmd_block_until_all_peers_started.c */ struct GNUNET_SCHEDULER_Task *finished_task; -/** - * Handle for a plugin. - */ -struct Plugin -{ - /** - * Name of the shared library. - */ - char *library_name; - - /** - * Plugin API. - */ - struct GNUNET_TESTING_PluginFunctions *api; - - /** - * IP address of the specific node the helper is running for. - * - */ - char *node_ip; - - /** - * Name of the test case plugin. - * - */ - char *plugin_name; - - /** - * The number of namespaces - * - */ - char *global_n; - - /** - * The number of local nodes per namespace. - * - */ - char *local_m; - - /** - * The number of the namespace this node is in. - * - */ - char *n; - - /** - * The number of the node in the namespace. - * - */ - char *m; -}; - /** * Struct with information about a specific node and the whole network namespace setup. * @@ -371,8 +320,8 @@ tokenizer_cb (void *cls, const struct GNUNET_MessageHeader *message) { struct NodeIdentifier *ni = cls; - const struct GNUNET_CMDS_HelperInit *msg; - struct GNUNET_CMDS_HelperReply *reply; + const struct GNUNET_TESTING_CommandHelperInit *msg; + struct GNUNET_TESTING_CommandHelperReply *reply; char *binary; char *plugin_name; size_t plugin_name_size; @@ -390,9 +339,9 @@ tokenizer_cb (void *cls, const struct GNUNET_MessageHeader *message) msize = ntohs (message->size); if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_INIT == ntohs (message->type)) { - msg = (const struct GNUNET_CMDS_HelperInit *) message; + msg = (const struct GNUNET_TESTING_CommandHelperInit *) message; plugin_name_size = ntohs (msg->plugin_name_size); - if ((sizeof(struct GNUNET_CMDS_HelperInit) + plugin_name_size) > msize) + if ((sizeof(struct GNUNET_TESTING_CommandHelperInit) + plugin_name_size) > msize) { GNUNET_break (0); LOG (GNUNET_ERROR_TYPE_WARNING, @@ -445,8 +394,8 @@ tokenizer_cb (void *cls, const struct GNUNET_MessageHeader *message) plugin->n, plugin->local_m, ni->topology_data, ni->read_file, &finished_cb); - msg_length = sizeof(struct GNUNET_CMDS_HelperReply); - reply = GNUNET_new (struct GNUNET_CMDS_HelperReply); + msg_length = sizeof(struct GNUNET_TESTING_CommandHelperReply); + reply = GNUNET_new (struct GNUNET_TESTING_CommandHelperReply); reply->header.type = htons (GNUNET_MESSAGE_TYPE_CMDS_HELPER_REPLY); reply->header.size = htons ((uint16_t) msg_length); @@ -458,6 +407,14 @@ tokenizer_cb (void *cls, const struct GNUNET_MessageHeader *message) return GNUNET_OK; } + else if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_BARRIER_ADVANCED == ntohs ( + message->type)) + { + struct GNUNET_TESTING_CommandBarrierAdvanced *adm = (struct GNUNET_TESTING_CommandBarrierAdvanced *) message; + + plugin->api->barrier_advanced (adm->barrier_name); + return GNUNET_OK; + } else if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_ALL_PEERS_STARTED == ntohs ( message->type)) { @@ -554,7 +511,8 @@ run (void *cls, { struct NodeIdentifier *ni = cls; - LOG_DEBUG ("Starting interpreter loop helper...\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Starting interpreter loop helper...\n"); tokenizer = GNUNET_MST_create (&tokenizer_cb, ni); stdin_fd = GNUNET_DISK_get_handle_from_native (stdin); @@ -564,6 +522,8 @@ run (void *cls, &read_task, NULL); GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Interpreter loop helper started.\n"); } @@ -662,6 +622,7 @@ main (int argc, char **argv) } shc_chld = GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death); + ret = GNUNET_PROGRAM_run (argc, argv, "gnunet-cmds-helper", diff --git a/src/testing/netjail_core.sh b/src/testing/netjail_core.sh deleted file mode 100755 index ef0a54a5e..000000000 --- a/src/testing/netjail_core.sh +++ /dev/null @@ -1,260 +0,0 @@ -#!/bin/sh -# - - -PREFIX=${PPID:?must run from a parent process} - -# running with `sudo` is required to be -# able running the actual commands as the -# original user. - -export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - -export RESULT= -export NAMESPACE_NUM=0 -export INTERFACE_NUM=0 - -netjail_next_namespace() { - local NUM=$NAMESPACE_NUM - NAMESPACE_NUM=$(($NAMESPACE_NUM + 1)) - RESULT=$NUM -} - -netjail_next_interface() { - local NUM=$INTERFACE_NUM - INTERFACE_NUM=$(($INTERFACE_NUM + 1)) - RESULT=$NUM -} - -netjail_opt() { - local OPT=$1 - shift 1 - - INDEX=1 - - while [ $# -gt 0 ]; do - if [ "$1" = "$OPT" ]; then - RESULT=$INDEX - return - fi - - INDEX=$(($INDEX + 1)) - shift 1 - done - - RESULT=0 -} - -netjail_opts() { - local OPT=$1 - local DEF=$2 - shift 2 - - while [ $# -gt 0 ]; do - if [ "$1" = "$OPT" ]; then - printf "$2" - return - fi - - shift 1 - done - - RESULT="$DEF" -} - -netjail_check() { - local NODE_COUNT=$1 - local FD_COUNT=$(($(ls /proc/self/fd | wc -w) - 4)) - - # quit if `$FD_COUNT < ($LOCAL_M * $GLOBAL_N * 2)`: - # the script also requires `sudo -C ($FD_COUNT + 4)` - # so you need 'Defaults closefrom_override' in the - # sudoers file. - - if [ $FD_COUNT -lt $(($NODE_COUNT * 2)) ]; then - echo "File descriptors do not match requirements!" >&2 - exit 1 - fi -} - -netjail_check_bin() { - local PROGRAM=$1 - local MATCH=$(ls $(echo $PATH | tr ":" "\n") | grep "^$PROGRAM\$" | tr "\n" " " | awk '{ print $1 }') - - # quit if the required binary $PROGRAM can not be - # found in the used $PATH. - - if [ "$MATCH" != "$PROGRAM" ]; then - echo "Required binary not found: $PROGRAM" >&2 - exit 1 - fi -} - -netjail_bridge() { - netjail_next_interface - local NUM=$RESULT - local BRIDGE=$(printf "%06x-%08x" $PREFIX $NUM) - - ip link add $BRIDGE type bridge - ip link set dev $BRIDGE up - - RESULT=$BRIDGE -} - -netjail_bridge_name() { - netjail_next_interface - local NUM=$RESULT - local BRIDGE=$(printf "%06x-%08x" $PREFIX $NUM) - - RESULT=$BRIDGE -} - -netjail_bridge_clear() { - local BRIDGE=$1 - - ip link delete $BRIDGE -} - -netjail_node() { - netjail_next_namespace - local NUM=$RESULT - local NODE=$(printf "%06x-%08x" $PREFIX $NUM) - - ip netns add $NODE - - RESULT=$NODE -} - -netjail_node_name() { - netjail_next_namespace - local NUM=$RESULT - local NODE=$(printf "%06x-%08x" $PREFIX $NUM) - - RESULT=$NODE -} - -netjail_node_clear() { - local NODE=$1 - - ip netns delete $NODE -} - -netjail_node_link_bridge() { - local NODE=$1 - local BRIDGE=$2 - local ADDRESS=$3 - local MASK=$4 - - netjail_next_interface - local NUM_IF=$RESULT - netjail_next_interface - local NUM_BR=$RESULT - - local LINK_IF=$(printf "%06x-%08x" $PREFIX $NUM_IF) - local LINK_BR=$(printf "%06x-%08x" $PREFIX $NUM_BR) - - ip link add $LINK_IF type veth peer name $LINK_BR - ip link set $LINK_IF netns $NODE - ip link set $LINK_BR master $BRIDGE - - ip -n $NODE addr add "$ADDRESS/$MASK" dev $LINK_IF - ip -n $NODE link set $LINK_IF up - ip -n $NODE link set up dev lo - - ip link set $LINK_BR up - - RESULT=$LINK_BR -} - -netjail_node_link_bridge_name() { - - netjail_next_interface - netjail_next_interface - local NUM_BR=$RESULT - - local LINK_BR=$(printf "%06x-%08x" $PREFIX $NUM_BR) - - RESULT=$LINK_BR -} - -netjail_node_unlink_bridge() { - local LINK_BR=$1 - - ip link delete $LINK_BR -} - -netjail_node_add_nat() { - local NODE=$1 - local ADDRESS=$2 - local MASK=$3 - - ip netns exec $NODE iptables -t nat -A POSTROUTING -s "$ADDRESS/$MASK" -j MASQUERADE -} - -netjail_node_add_default() { - local NODE=$1 - local ADDRESS=$2 - - ip -n $NODE route add default via $ADDRESS -} - -netjail_node_exec() { - JAILOR=${SUDO_USER:?must run in sudo} - local NODE=$1 - local FD_IN=$2 - local FD_OUT=$3 - shift 3 - - ip netns exec $NODE sudo -u $JAILOR -- $@ 1>& $FD_OUT 0<& $FD_IN -} - -netjail_node_exec_without_fds() { - JAILOR=${SUDO_USER:?must run in sudo} - NODE=$1 - shift 1 - - ip netns exec $NODE sudo -u $JAILOR -- $@ -} - -netjail_node_exec_without_fds_and_sudo() { - NODE=$1 - shift 1 - - ip netns exec $NODE $@ -} - -netjail_kill() { - local PID=$1 - local MATCH=$(ps --pid $PID | awk "{ if ( \$1 == $PID ) { print \$1 } }" | wc -l) - - if [ $MATCH -gt 0 ]; then - kill -n 19 $PID - - for CHILD in $(ps -o pid,ppid -ax | awk "{ if ( \$2 == $PID ) { print \$1 } }"); do - netjail_kill $CHILD - done - - kill $PID - fi -} - -netjail_killall() { - if [ $# -gt 0 ]; then - local PIDS=$1 - - for PID in $PIDS; do - netjail_kill $PID - done - fi -} - -netjail_waitall() { - if [ $# -gt 0 ]; then - local PIDS=$1 - - for PID in $PIDS; do - wait $PID - done - fi -} - diff --git a/src/testing/netjail_exec.sh b/src/testing/netjail_exec.sh deleted file mode 100755 index cd993a39b..000000000 --- a/src/testing/netjail_exec.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh -. "./../testing/netjail_core.sh" - -set -eu -set -x - -export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - -M=$1 -N=$2 - -NODE=$6 - -netjail_node_exec_without_fds_and_sudo $NODE $3 $4 $5 $1 $2 diff --git a/src/testing/netjail_start.sh b/src/testing/netjail_start.sh deleted file mode 100755 index 1dfe1dfdf..000000000 --- a/src/testing/netjail_start.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/bash -. "./../testing/netjail_core.sh" -. "./../testing/topo.sh" - -set -eu -set -x - -export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - -filename=$1 -PREFIX=$2 - -read_topology $filename - -shift 2 - -LOCAL_GROUP="192.168.15" -GLOBAL_GROUP="92.68.150" -KNOWN_GROUP="92.68.151" - - -echo "Start [local: $LOCAL_GROUP.0/24, global: $GLOBAL_GROUP.0/16]" - -netjail_bridge -NETWORK_NET=$RESULT - -for X in $(seq $KNOWN); do - netjail_node - KNOWN_NODES[$X]=$RESULT - netjail_node_link_bridge ${KNOWN_NODES[$X]} $NETWORK_NET "$KNOWN_GROUP.$X" 16 - KNOWN_LINKS[$X]=$RESULT -done - -declare -A NODES -declare -A NODE_LINKS - -for N in $(seq $GLOBAL_N); do - netjail_node - ROUTERS[$N]=$RESULT - netjail_node_link_bridge ${ROUTERS[$N]} $NETWORK_NET "$GLOBAL_GROUP.$N" 16 - NETWORK_LINKS[$N]=$RESULT - netjail_bridge - ROUTER_NETS[$N]=$RESULT - - for M in $(seq $LOCAL_M); do - netjail_node - NODES[$N,$M]=$RESULT - netjail_node_link_bridge ${NODES[$N,$M]} ${ROUTER_NETS[$N]} "$LOCAL_GROUP.$M" 24 - NODE_LINKS[$N,$M]=$RESULT - done - - ROUTER_ADDR="$LOCAL_GROUP.$(($LOCAL_M+1))" - netjail_node_link_bridge ${ROUTERS[$N]} ${ROUTER_NETS[$N]} $ROUTER_ADDR 24 - ROUTER_LINKS[$N]=$RESULT - - netjail_node_add_nat ${ROUTERS[$N]} $ROUTER_ADDR 24 - - for M in $(seq $LOCAL_M); do - netjail_node_add_default ${NODES[$N,$M]} $ROUTER_ADDR - done - - # TODO Topology configuration must be enhanced to configure forwarding to more than one subnet node via different ports. - - if [ "1" == "${R_TCP[$N]}" ] - then - ip netns exec ${ROUTERS[$N]} iptables -t nat -A PREROUTING -p tcp -d $GLOBAL_GROUP.$N --dport 60002 -j DNAT --to $LOCAL_GROUP.1 - ip netns exec ${ROUTERS[$N]} iptables -A FORWARD -d $LOCAL_GROUP.1 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT - fi - if [ "1" == "${R_UDP[$N]}" ] - then - ip netns exec ${ROUTERS[$N]} iptables -t nat -A PREROUTING -p udp -d $GLOBAL_GROUP.$N --dport 60002 -j DNAT --to $LOCAL_GROUP.1 - ip netns exec ${ROUTERS[$N]} iptables -A FORWARD -d $LOCAL_GROUP.1 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT - fi -done diff --git a/src/testing/netjail_stop.sh b/src/testing/netjail_stop.sh deleted file mode 100755 index abfaf3acf..000000000 --- a/src/testing/netjail_stop.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash -. "./../testing/netjail_core.sh" -. "./../testing/topo.sh" - -set -eu -set -x - -export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - -filename=$1 -PREFIX=$2 - -read_topology $filename - -declare -A NODES -declare -A NODE_LINKS - -netjail_bridge_name -NETWORK_NET=$RESULT - -for X in $(seq $KNOWN); do - netjail_node_name - KNOWN_NODES[$X]=$RESULT - netjail_node_link_bridge_name - KNOWN_LINKS[$X]=$RESULT - netjail_node_unlink_bridge ${KNOWN_LINKS[$X]} - netjail_node_clear ${KNOWN_NODES[$X]} -done - -for N in $(seq $GLOBAL_N); do - netjail_node_name - ROUTERS[$N]=$RESULT - netjail_node_link_bridge_name - NETWORK_LINKS[$N]=$RESULT - netjail_bridge_name - ROUTER_NETS[$N]=$RESULT - netjail_node_link_bridge_name - ROUTER_LINKS[$N]=$RESULT - - netjail_node_unlink_bridge ${ROUTER_LINKS[$N]} - - for M in $(seq $LOCAL_M); do - netjail_node_name - NODES[$N,$M]=$RESULT - netjail_node_link_bridge_name - NODE_LINKS[$N,$M]=$RESULT - netjail_node_unlink_bridge ${NODE_LINKS[$N,$M]} - netjail_node_clear ${NODES[$N,$M]} - done - - - netjail_bridge_clear ${ROUTER_NETS[$N]} - netjail_node_unlink_bridge ${NETWORK_LINKS[$N]} - netjail_node_clear ${ROUTERS[$N]} -done - -netjail_bridge_clear $NETWORK_NET - -echo "Done" diff --git a/src/testing/testing.c b/src/testing/testing.c index d18197860..de6bc45f5 100644 --- a/src/testing/testing.c +++ b/src/testing/testing.c @@ -2136,6 +2136,27 @@ get_node_info (unsigned int num, GNUNET_free (hkey); } +/** + * Get a node from the topology. + * + * @param num The specific node we want the connections for. + * @param topology The topology we get the connections from. + * @return The connections of the node. + */ +struct GNUNET_TESTING_NetjailNode * +GNUNET_TESTING_get_node (unsigned int num, + struct GNUNET_TESTING_NetjailTopology *topology) +{ + struct GNUNET_TESTING_NetjailNode *node; + struct GNUNET_TESTING_NetjailNamespace *namespace; + struct GNUNET_TESTING_NodeConnection *node_connections; + + get_node_info (num, topology, &node, &namespace, &node_connections); + + return node; + +} + /** * Get the connections to other nodes for a specific node. @@ -2208,7 +2229,7 @@ free_nodes_cb (void *cls, pos_connection); GNUNET_free (pos_connection); } - + GNUNET_free (node->plugin); GNUNET_free (node); return GNUNET_OK; @@ -2225,7 +2246,7 @@ free_namespaces_cb (void *cls, GNUNET_free (namespace->router); GNUNET_CONTAINER_multishortmap_iterate (namespace->nodes, free_nodes_cb, - NULL); + namespace->nodes); return GNUNET_OK; } diff --git a/src/testing/testing_api_cmd_barrier.c b/src/testing/testing_api_cmd_barrier.c new file mode 100644 index 000000000..b0293f2c7 --- /dev/null +++ b/src/testing/testing_api_cmd_barrier.c @@ -0,0 +1,256 @@ +/* + This file is part of GNUnet + Copyright (C) 2022 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + SPDX-License-Identifier: AGPL3.0-or-later + */ + +/** + * @file testing/testing_api_cmd_barrier.c + * @brief Barrier functionality. + * @author t3sserakt + */ +#include "platform.h" +#include "gnunet_testing_ng_lib.h" +#include "gnunet_testing_barrier.h" + +struct BarrierState +{ + /* + * Our barrier. + */ + struct GNUNET_TESTING_Barrier *barrier; + + /* + * Our label. + */ + const char *label; +}; + + +/** + * Send Message to master loop that cmds being attached to a barrier. + * + * @param is The interpreter loop. + * @param barrier_name The name of the barrier to advance. + * @param subnet_number The number of the subnet. + * @param node_number The node to inform. + * @param write_message Callback to write messages to the master loop. + */ +void +GNUNET_TESTING_send_barrier_attach (struct GNUNET_TESTING_Interpreter *is, + char *barrier_name, + unsigned int global_node_number, + unsigned int expected_reaches, + TESTING_CMD_HELPER_write_cb write_message) +{ + struct GNUNET_TESTING_CommandBarrierAttached *atm = GNUNET_new (struct GNUNET_TESTING_CommandBarrierAttached); + size_t msg_length = sizeof(struct GNUNET_TESTING_CommandBarrierAttached); + + atm->header.type = htons (GNUNET_MESSAGE_TYPE_CMDS_HELPER_BARRIER_ATTACHED); + atm->header.size = htons ((uint16_t) msg_length); + atm->barrier_name = barrier_name; + atm->expected_reaches = expected_reaches; + atm->node_number = global_node_number; + write_message ((struct GNUNET_MessageHeader *) atm, msg_length); + + GNUNET_free (atm); +} + + +/** + * Send Message to netjail nodes that a barrier can be advanced. + * + * @param is The interpreter loop. + * @param barrier_name The name of the barrier to advance. + * @param global_node_number The global number of the node to inform. + */ +void +GNUNET_TESTING_send_barrier_advance (struct GNUNET_TESTING_Interpreter *is, + const char *barrier_name, + unsigned int global_node_number) +{ + struct GNUNET_TESTING_CommandBarrierAdvanced *adm = GNUNET_new (struct GNUNET_TESTING_CommandBarrierAdvanced); + size_t msg_length = sizeof(struct GNUNET_TESTING_CommandBarrierAdvanced); + + adm->header.type = htons (GNUNET_MESSAGE_TYPE_CMDS_HELPER_BARRIER_ADVANCED); + adm->header.size = htons ((uint16_t) msg_length); + adm->barrier_name = barrier_name; + GNUNET_TESTING_send_message_to_netjail (is, + global_node_number, + &adm->header); + GNUNET_free (adm); +} + + +/** + * Can we advance the barrier? + * + * @param barrier The barrier in question. + * @return GNUNET_YES if we can advance the barrier, GNUNET_NO if not. + */ +unsigned int +GNUNET_TESTING_can_barrier_advance (struct GNUNET_TESTING_Barrier *barrier) +{ + unsigned int expected_reaches = barrier->expected_reaches; + unsigned int reached = barrier->reached; + double percentage_to_be_reached = barrier->percentage_to_be_reached; + unsigned int number_to_be_reached = barrier->number_to_be_reached; + + if ((0 < percentage_to_be_reached && + (double)expected_reaches/reached*100) >= percentage_to_be_reached || + (0 < number_to_be_reached && reached >= number_to_be_reached )) + { + return GNUNET_YES; + } + else + { + return GNUNET_NO; + } +} + + +/** + * Offer internal data from a "barrier" CMD, to other commands. + * + * @param cls closure. + * @param[out] ret result. + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static enum GNUNET_GenericReturnValue +barrier_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct BarrierState *bs = cls; + + struct GNUNET_TESTING_Trait traits[] = { + GNUNET_TESTING_trait_end () + }; + + /* Always return current command. */ + return GNUNET_TESTING_get_trait (traits, + ret, + trait, + index); +} + +/** + * Cleanup the state from a "barrier" CMD, and possibly + * cancel a pending operation thereof. + * + * @param cls closure. + */ +static void +barrier_cleanup (void *cls) +{ + struct BarrierState *brs = cls; + + GNUNET_free (brs->barrier); + GNUNET_free (brs); +} + +/** + * Run the command. + * + * @param cls closure. + * @param is the interpreter state. + */ +static void +barrier_run (void *cls, + struct GNUNET_TESTING_Interpreter *is) +{ + struct BarrierState *brs = cls; + + GNUNET_TESTING_barrier_add (is, brs->barrier); +} + +/** + * Adding a node to the map of nodes of a barrier. + * + * @param nodes Map of nodes. + * @param node The node to add. + */ +void +GNUNET_TESTING_barrier_add_node (struct GNUNET_CONTAINER_MultiShortmap *nodes, + struct GNUNET_TESTING_NetjailNode *node) +{ + struct GNUNET_HashCode hc; + struct GNUNET_ShortHashCode key; + + GNUNET_CRYPTO_hash (&(node->node_number), sizeof(node->node_number), &hc); + memcpy (&key, &hc, sizeof (key)); + GNUNET_CONTAINER_multishortmap_put (nodes, + &key, + node, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); +} + + +/** + * Getting a node from a map by global node number. + * + * @param nodes The map. + * @param node_number The global node number. + * @return The node. + */ +struct GNUNET_TESTING_NetjailNode * +GNUNET_TESTING_barrier_get_node (struct GNUNET_CONTAINER_MultiShortmap *nodes, + unsigned int node_number) +{ + struct GNUNET_HashCode hc; + struct GNUNET_ShortHashCode *key; + + GNUNET_CRYPTO_hash (&(node_number), sizeof(node_number), &hc); + memcpy (&key, + &hc, + sizeof (key)); + return GNUNET_CONTAINER_multishortmap_get (nodes, key); +} + + +struct GNUNET_TESTING_Command +GNUNET_TESTING_cmd_barrier_create (const char *label, + double percentage_to_be_reached, + unsigned int number_to_be_reached) +{ + struct GNUNET_TESTING_Barrier *barrier; + struct BarrierState *bs; + + bs = GNUNET_new (struct BarrierState); + bs->label = label; + barrier = GNUNET_new (struct GNUNET_TESTING_Barrier); + barrier->name = label; + GNUNET_assert (0 < percentage_to_be_reached && 0 == number_to_be_reached || + 0 == percentage_to_be_reached && 0 < number_to_be_reached); + barrier->percentage_to_be_reached; + barrier->number_to_be_reached; + bs->barrier = barrier; + { + struct GNUNET_TESTING_Command cmd = { + .cls = bs, + .label = label, + .run = &barrier_run, + .cleanup = &barrier_cleanup, + .traits = &barrier_traits + }; + + return cmd; + } +} diff --git a/src/testing/testing_api_cmd_barrier_reached.c b/src/testing/testing_api_cmd_barrier_reached.c new file mode 100644 index 000000000..7e6f58fc1 --- /dev/null +++ b/src/testing/testing_api_cmd_barrier_reached.c @@ -0,0 +1,214 @@ +/* + This file is part of GNUnet + Copyright (C) 2022 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + SPDX-License-Identifier: AGPL3.0-or-later + */ + +/** + * @file testing/testing_api_cmd_barrier_reached.c + * @brief Command to signal barrier was reached. + * @author t3sserakt + */ +#include "platform.h" +#include "gnunet_testing_ng_lib.h" +#include "gnunet_testing_barrier.h" + +/** + * Struct with information for callbacks. + * + */ +struct BarrierReachedState +{ + /** + * Callback to write messages to the master loop. + * + */ + TESTING_CMD_HELPER_write_cb write_message; + + /** + * Context for our asynchronous completion. + */ + struct GNUNET_TESTING_AsyncContext ac; + + /** + * The label of this command. + */ + const char *label; + + /** + * The name of the barrier this commands wait (if finishing asynchronous) for or/and reaches. + */ + const char *barrier_name; + + /* + * The global numer of the node the cmd runs on. + */ + unsigned int node_number; + + /** + * If this command will block. + */ + unsigned int asynchronous_finish; + + /** + * Is this cmd running on the master loop. + */ + unsigned int running_on_master; +}; + + +/** + * Run the command. + * + * @param cls closure. + * @param is the interpreter state. + */ +static void +barrier_reached_run (void *cls, + struct GNUNET_TESTING_Interpreter *is) +{ + struct BarrierReachedState *brs = cls; + struct GNUNET_TESTING_Barrier *barrier; + struct GNUNET_TESTING_Command *cmd; + size_t msg_length; + struct GNUNET_TESTING_CommandBarrierReached *msg; + + barrier = GNUNET_TESTING_get_barrier (is, brs->barrier_name); + if (NULL == barrier) + { + barrier = GNUNET_new (struct GNUNET_TESTING_Barrier); + barrier->shadow = GNUNET_YES; + barrier->name = brs->label; + GNUNET_TESTING_barrier_add (is, barrier); + } + barrier->reached++; + if (GNUNET_TESTING_can_barrier_advance (barrier)) + { + cmd->asynchronous_finish = GNUNET_YES; + GNUNET_TESTING_finish_attached_cmds (is, barrier); + } + else if (GNUNET_NO == brs->asynchronous_finish) + { + cmd = GNUNET_TESTING_interpreter_get_current_command (is); + GNUNET_CONTAINER_DLL_insert (barrier->cmds_head, + barrier->cmds_tail, + cmd); + } + else + { + cmd->asynchronous_finish = GNUNET_YES; + } + if (GNUNET_NO == brs->running_on_master) + { + msg_length = sizeof(struct GNUNET_TESTING_CommandBarrierReached); + msg = GNUNET_new (struct GNUNET_TESTING_CommandBarrierReached); + msg->header.size = htons ((uint16_t) msg_length); + msg->header.type = htons(GNUNET_MESSAGE_TYPE_CMDS_HELPER_BARRIER_REACHED); + msg->barrier_name = barrier->name; + msg->node_number = brs->node_number; + brs->write_message ((struct GNUNET_MessageHeader *) msg, msg_length); + } +} + + +/** + * Cleanup the state from a "barrier reached" CMD, and possibly + * cancel a pending operation thereof. + * + * @param cls closure. + */ +static void +barrier_reached_cleanup (void *cls) +{ + struct BarrierReachedState *brs = cls; + + GNUNET_free (brs); +} + + +/** + * Offer internal data from a "batch" CMD, to other commands. + * + * @param cls closure. + * @param[out] ret result. + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static enum GNUNET_GenericReturnValue +barrier_reached_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct BarrierReachedState *brs = cls; + struct GNUNET_TESTING_AsyncContext *ac = &brs->ac; + + struct GNUNET_TESTING_Trait traits[] = { + GNUNET_TESTING_make_trait_async_context ((const void *) ac), + GNUNET_TESTING_trait_end () + }; + + return GNUNET_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Create command. + * + * @param label name for command. + * @param barrier_label The name of the barrier we wait for (if finishing asynchronous) and which will be reached. + * @param asynchronous_finish If GNUNET_YES this command will not block. Can be NULL. + * @param node_number The global numer of the node the cmd runs on. + * @param running_on_master Is this cmd running on the master loop. + * @param write_message Callback to write messages to the master loop. + * @return command. + */ +struct GNUNET_TESTING_Command +GNUNET_TESTING_cmd_barrier_reached ( + const char *label, + const char *barrier_label, + unsigned int asynchronous_finish, + unsigned int node_number, + unsigned int running_on_master, + TESTING_CMD_HELPER_write_cb write_message) +{ + struct BarrierReachedState *brs; + + brs = GNUNET_new (struct BarrierReachedState); + brs->label = label; + brs->barrier_name = barrier_label; + brs->asynchronous_finish = asynchronous_finish; + brs->node_number = node_number; + brs->running_on_master = running_on_master; + brs->write_message = write_message; + { + struct GNUNET_TESTING_Command cmd = { + .cls = brs, + .label = label, + .run = &barrier_reached_run, + .ac = &brs->ac, + .cleanup = &barrier_reached_cleanup, + .traits = &barrier_reached_traits + }; + + return cmd; + } +} diff --git a/src/testing/testing_api_cmd_block_until_external_trigger.c b/src/testing/testing_api_cmd_block_until_external_trigger.c index f51b2109b..347791b7a 100644 --- a/src/testing/testing_api_cmd_block_until_external_trigger.c +++ b/src/testing/testing_api_cmd_block_until_external_trigger.c @@ -97,8 +97,6 @@ block_until_all_peers_started_run (void *cls, * Create command. * * @param label name for command. - * @param all_peers_started Flag which will be set from outside. - * @param asynchronous_finish If GNUNET_YES this command will not block. Can be NULL. * @return command. */ struct GNUNET_TESTING_Command diff --git a/src/testing/testing_api_cmd_local_test_prepared.c b/src/testing/testing_api_cmd_local_test_prepared.c index e71d3ef45..0b88586e8 100644 --- a/src/testing/testing_api_cmd_local_test_prepared.c +++ b/src/testing/testing_api_cmd_local_test_prepared.c @@ -80,11 +80,11 @@ local_test_prepared_run (void *cls, { struct LocalPreparedState *lfs = cls; - struct GNUNET_CMDS_LOCAL_TEST_PREPARED *reply; + struct GNUNET_TESTING_CommandLocalTestPrepared *reply; size_t msg_length; - msg_length = sizeof(struct GNUNET_CMDS_LOCAL_TEST_PREPARED); - reply = GNUNET_new (struct GNUNET_CMDS_LOCAL_TEST_PREPARED); + msg_length = sizeof(struct GNUNET_TESTING_CommandLocalTestPrepared); + reply = GNUNET_new (struct GNUNET_TESTING_CommandLocalTestPrepared); reply->header.type = htons ( GNUNET_MESSAGE_TYPE_CMDS_HELPER_LOCAL_TEST_PREPARED); reply->header.size = htons ((uint16_t) msg_length); diff --git a/src/testing/testing_api_cmd_netjail_start_testsystem.c b/src/testing/testing_api_cmd_netjail_start_testsystem.c index 98de0698a..4b2fbcc56 100644 --- a/src/testing/testing_api_cmd_netjail_start_testsystem.c +++ b/src/testing/testing_api_cmd_netjail_start_testsystem.c @@ -27,6 +27,7 @@ #include "gnunet_testing_ng_lib.h" #include "gnunet_testing_netjail_lib.h" #include "testing_cmds.h" +#include "gnunet_testing_barrier.h" #define NETJAIL_EXEC_SCRIPT "netjail_exec.sh" @@ -167,11 +168,16 @@ struct NetJailState }; /** - * Struct containing the number of the test environment and the NetJailState which + * Struct containing the number of the netjail node and the NetJailState which * will be handed to callbacks specific to a test environment. */ struct TestingSystemCount { + /** + * The plugin correlated to this netjail node. + */ + struct Plugin *plugin; + /** * Kept in a DLL. */ @@ -187,12 +193,6 @@ struct TestingSystemCount */ struct GNUNET_HELPER_SendHandle *shandle; - /** - * The number of the test environment. - * - */ - unsigned int count; - /** * Struct to store information handed over to callbacks. * @@ -214,7 +214,7 @@ static void netjail_exec_cleanup (void *cls) { struct NetJailState *ns = cls; - + GNUNET_TESTING_delete_barriers (ns->is); GNUNET_free (ns); } @@ -259,10 +259,10 @@ clear_msg (void *cls, int result) struct TestingSystemCount *tbc = cls; GNUNET_assert (NULL != tbc->shandle); - /*GNUNET_free (tbc->shandle); - tbc->shandle = NULL;*/ - GNUNET_free (tbc->msg); - tbc->msg = NULL; + //GNUNET_free (tbc->shandle); + GNUNET_free (tbc->plugin); + tbc->shandle = NULL; + GNUNET_free (tbc); } @@ -276,19 +276,19 @@ send_message_to_locals ( { const struct GNUNET_HELPER_Handle *helper; struct TestingSystemCount *tbc; + unsigned int count; LOG (GNUNET_ERROR_TYPE_DEBUG, "send message of type %u to locals\n", header->type); tbc = GNUNET_new (struct TestingSystemCount); tbc->ns = ns; - // TODO This needs to be more generic. As we send more messages back and forth, we can not grow the arrays again and again, because this is to error prone. if (0 == i) - tbc->count = j; // + total_number; + count = j; else - tbc->count = (i - 1) * ns->local_m + j + ns->known; // + total_number ; + count = (i - 1) * ns->local_m + j + ns->known; - helper = ns->helper[tbc->count - 1];// - total_number]; + helper = ns->helper[count - 1]; @@ -303,16 +303,33 @@ send_message_to_locals ( } +static void +send_barrier_advanced (struct GNUNET_TESTING_CommandBarrierReached *rm, + unsigned int i, + unsigned int j, + struct NetJailState *ns) +{ + struct GNUNET_TESTING_CommandBarrierAdvanced *adm = GNUNET_new (struct GNUNET_TESTING_CommandBarrierAdvanced); + size_t msg_length = sizeof(struct GNUNET_TESTING_CommandAllLocalTestsPrepared); + + adm->header.type = htons (GNUNET_MESSAGE_TYPE_CMDS_HELPER_ALL_PEERS_STARTED); + adm->header.size = htons ((uint16_t) msg_length); + adm->barrier_name = rm->barrier_name; + send_message_to_locals (i, j, ns, &adm->header); + GNUNET_free (adm); +} + + static void send_all_local_tests_prepared (unsigned int i, unsigned int j, struct NetJailState *ns) { - struct GNUNET_CMDS_ALL_LOCAL_TESTS_PREPARED *reply; + struct GNUNET_TESTING_CommandAllLocalTestsPrepared *reply; size_t msg_length; - msg_length = sizeof(struct GNUNET_CMDS_ALL_LOCAL_TESTS_PREPARED); - reply = GNUNET_new (struct GNUNET_CMDS_ALL_LOCAL_TESTS_PREPARED); + msg_length = sizeof(struct GNUNET_TESTING_CommandAllLocalTestsPrepared); + reply = GNUNET_new (struct GNUNET_TESTING_CommandAllLocalTestsPrepared); reply->header.type = htons ( GNUNET_MESSAGE_TYPE_CMDS_HELPER_ALL_LOCAL_TESTS_PREPARED); reply->header.size = htons ((uint16_t) msg_length); @@ -325,13 +342,11 @@ send_all_local_tests_prepared (unsigned int i, unsigned int j, struct static void send_all_peers_started (unsigned int i, unsigned int j, struct NetJailState *ns) { - - struct GNUNET_CMDS_ALL_PEERS_STARTED *reply; + struct GNUNET_TESTING_CommandAllPeersStarted *reply; size_t msg_length; - - msg_length = sizeof(struct GNUNET_CMDS_ALL_PEERS_STARTED); - reply = GNUNET_new (struct GNUNET_CMDS_ALL_PEERS_STARTED); + msg_length = sizeof(struct GNUNET_TESTING_CommandAllPeersStarted); + reply = GNUNET_new (struct GNUNET_TESTING_CommandAllPeersStarted); reply->header.type = htons ( GNUNET_MESSAGE_TYPE_CMDS_HELPER_ALL_PEERS_STARTED); reply->header.size = htons ((uint16_t) msg_length); @@ -341,6 +356,44 @@ send_all_peers_started (unsigned int i, unsigned int j, struct NetJailState *ns) } +void +barrier_attached (struct NetJailState *ns, const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_TESTING_CommandBarrierAttached *am; + struct GNUNET_TESTING_NetjailNode *node; + struct GNUNET_TESTING_Barrier *barrier; + + am = (struct GNUNET_TESTING_CommandBarrierAttached *) message; + barrier = GNUNET_TESTING_get_barrier (ns->is, am->barrier_name); + GNUNET_assert (NULL != barrier && GNUNET_NO == barrier->shadow); + node = GNUNET_TESTING_barrier_get_node (barrier->nodes, am->node_number); + if (NULL == node) + { + node = GNUNET_new (struct GNUNET_TESTING_NetjailNode); + node->node_number = am->node_number; + GNUNET_TESTING_barrier_add_node (barrier->nodes, node); + } + node->expected_reaches = node->expected_reaches + am->expected_reaches; + barrier->expected_reaches = barrier->expected_reaches + am->expected_reaches; +} + + +void +barrier_reached (struct NetJailState *ns, const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_TESTING_CommandBarrierReached *rm = (struct GNUNET_TESTING_CommandBarrierReached *) message; + struct GNUNET_TESTING_Barrier *barrier = GNUNET_TESTING_get_barrier (ns->is, rm->barrier_name); + struct GNUNET_TESTING_NetjailNode *node; + + GNUNET_assert (NULL != barrier && GNUNET_NO == barrier->shadow); + barrier->reached++; + if (GNUNET_TESTING_can_barrier_advance (barrier)) + { + GNUNET_TESTING_finish_attached_cmds (ns->is, barrier); + } +} + + /** * Functions with this signature are called whenever a * complete message is received by the tokenizer. @@ -356,63 +409,68 @@ send_all_peers_started (unsigned int i, unsigned int j, struct NetJailState *ns) static int helper_mst (void *cls, const struct GNUNET_MessageHeader *message) { - // struct TestingSystemCount *tbc = cls; struct NetJailState *ns = cls; unsigned int total_number = ns->local_m * ns->global_n + ns->known; uint16_t message_type = ntohs (message->type); switch (message_type) { - case GNUNET_MESSAGE_TYPE_CMDS_HELPER_REPLY: - ns->number_of_testsystems_started++; - break; - case GNUNET_MESSAGE_TYPE_CMDS_HELPER_PEER_STARTED: - ns->number_of_peers_started++; - if (ns->number_of_peers_started == total_number) - { - for (int i = 1; i <= ns->known; i++) - { - send_all_peers_started (0,i, ns); - } - for (int i = 1; i <= ns->global_n; i++) + case GNUNET_MESSAGE_TYPE_CMDS_HELPER_BARRIER_ATTACHED: + barrier_attached (ns, message); + break; + case GNUNET_MESSAGE_TYPE_CMDS_HELPER_BARRIER_REACHED: + barrier_reached (ns, message); + break; + case GNUNET_MESSAGE_TYPE_CMDS_HELPER_REPLY: + ns->number_of_testsystems_started++; + break; + case GNUNET_MESSAGE_TYPE_CMDS_HELPER_PEER_STARTED: + ns->number_of_peers_started++; + if (ns->number_of_peers_started == total_number) { - for (int j = 1; j <= ns->local_m; j++) + for (int i = 1; i <= ns->known; i++) + { + send_all_peers_started (0,i, ns); + } + for (int i = 1; i <= ns->global_n; i++) { - send_all_peers_started (i,j, ns); + for (int j = 1; j <= ns->local_m; j++) + { + send_all_peers_started (i,j, ns); + } } + ns->number_of_peers_started = 0; } - ns->number_of_peers_started = 0; - } - break; - case GNUNET_MESSAGE_TYPE_CMDS_HELPER_LOCAL_TEST_PREPARED: - ns->number_of_local_tests_prepared++; - if (ns->number_of_local_tests_prepared == total_number) - { - for (int i = 1; i <= ns->known; i++) + break; + case GNUNET_MESSAGE_TYPE_CMDS_HELPER_LOCAL_TEST_PREPARED: + ns->number_of_local_tests_prepared++; + if (ns->number_of_local_tests_prepared == total_number) { - send_all_local_tests_prepared (0,i, ns); - } + for (int i = 1; i <= ns->known; i++) + { + send_all_local_tests_prepared (0,i, ns); + } - for (int i = 1; i <= ns->global_n; i++) - { - for (int j = 1; j <= ns->local_m; j++) + for (int i = 1; i <= ns->global_n; i++) { - send_all_local_tests_prepared (i,j, ns); + for (int j = 1; j <= ns->local_m; j++) + { + send_all_local_tests_prepared (i,j, ns); + } } } - } - break; - case GNUNET_MESSAGE_TYPE_CMDS_HELPER_LOCAL_FINISHED: - ns->number_of_local_tests_finished++; - if (ns->number_of_local_tests_finished == total_number) - { - GNUNET_SCHEDULER_cancel (ns->timeout_task); - GNUNET_TESTING_async_finish (&ns->ac); - } - break; - default: - // We received a message we can not handle. - GNUNET_assert (0); + break; + case GNUNET_MESSAGE_TYPE_CMDS_HELPER_LOCAL_FINISHED: + ns->number_of_local_tests_finished++; + if (ns->number_of_local_tests_finished == total_number) + { + GNUNET_SCHEDULER_cancel (ns->timeout_task); + GNUNET_TESTING_async_finish (&ns->ac); + } + break; + default: + // We received a message we can not handle. + GNUNET_assert (0); } LOG (GNUNET_ERROR_TYPE_DEBUG, @@ -454,16 +512,16 @@ exp_cb (void *cls) * @param plugin_name Name of the test case plugin the helper will load. * */ -static struct GNUNET_CMDS_HelperInit * +static struct GNUNET_TESTING_CommandHelperInit * create_helper_init_msg_ (const char *plugin_name) { - struct GNUNET_CMDS_HelperInit *msg; + struct GNUNET_TESTING_CommandHelperInit *msg; uint16_t plugin_name_len; uint16_t msg_size; GNUNET_assert (NULL != plugin_name); plugin_name_len = strlen (plugin_name); - msg_size = sizeof(struct GNUNET_CMDS_HelperInit) + plugin_name_len; + msg_size = sizeof(struct GNUNET_TESTING_CommandHelperInit) + plugin_name_len; msg = GNUNET_malloc (msg_size); msg->header.size = htons (msg_size); msg->header.type = htons (GNUNET_MESSAGE_TYPE_CMDS_HELPER_INIT); @@ -484,8 +542,9 @@ start_helper (struct NetJailState *ns, unsigned int m, unsigned int n) { + struct Plugin *plugin; struct GNUNET_HELPER_Handle *helper; - struct GNUNET_CMDS_HelperInit *msg; + struct GNUNET_TESTING_CommandHelperInit *msg; struct TestingSystemCount *tbc; char *m_char; char *n_char; @@ -493,7 +552,7 @@ start_helper (struct NetJailState *ns, char *local_m_char; char *known_char; char *node_id; - char *plugin; + char *plugin_name; char *read_file; pid_t pid; unsigned int script_num; @@ -501,10 +560,13 @@ start_helper (struct NetJailState *ns, struct GNUNET_HashCode hc; struct GNUNET_TESTING_NetjailTopology *topology = ns->topology; struct GNUNET_TESTING_NetjailNode *node; + struct GNUNET_TESTING_NetjailNode *barrier_node; struct GNUNET_TESTING_NetjailNamespace *namespace; char *data_dir; char *script_name; - + struct GNUNET_TESTING_Barrier *barriers; + struct GNUNET_TESTING_Barrier *pos; + struct GNUNET_TESTING_Barrier *barrier; if (0 == n) script_num = m - 1; @@ -579,11 +641,12 @@ start_helper (struct NetJailState *ns, GNUNET_array_append (ns->helper, ns->n_helper, helper); } - tbc->count = ns->n_helper; - hkey = GNUNET_new (struct GNUNET_ShortHashCode); + GNUNET_TESTING_add_netjail_helper (ns->is, + helper); - plugin = topology->plugin; + plugin_name = topology->plugin; + hkey = GNUNET_new (struct GNUNET_ShortHashCode); if (0 == m) { @@ -597,7 +660,7 @@ start_helper (struct NetJailState *ns, node = GNUNET_CONTAINER_multishortmap_get (topology->map_globals, hkey); if (NULL != node->plugin) - plugin = node->plugin; + plugin_name = node->plugin; } } @@ -622,24 +685,47 @@ start_helper (struct NetJailState *ns, node = GNUNET_CONTAINER_multishortmap_get (namespace->nodes, hkey); if (NULL != node->plugin) - plugin = node->plugin; + plugin_name = node->plugin; } } } - msg = create_helper_init_msg_ (plugin); + plugin = GNUNET_new (struct Plugin); + plugin->api = GNUNET_PLUGIN_load (plugin_name, + NULL); + barriers = plugin->api->get_waiting_for_barriers (); + + + for (pos = barriers; NULL != pos; pos = pos->next) + { + barrier = GNUNET_TESTING_get_barrier (ns->is, pos->name); + if (NULL == barrier || GNUNET_YES == barrier->shadow) + { + GNUNET_TESTING_barrier_add (ns->is, pos); + barrier = pos; + barrier->nodes = GNUNET_CONTAINER_multishortmap_create (1,GNUNET_NO); + } + GNUNET_assert (NULL != node); + barrier_node = GNUNET_new (struct GNUNET_TESTING_NetjailNode); + barrier_node->node_number = node->node_number; + barrier_node->expected_reaches = pos->expected_reaches; + barrier->expected_reaches = barrier->expected_reaches + pos->expected_reaches; + GNUNET_TESTING_barrier_add_node (barrier->nodes, node); + } + tbc->plugin = plugin; + + msg = create_helper_init_msg_ (plugin_name); - // GNUNET_array_append (tbc->shandle, tbc->n_shandle, tbc->shandle = GNUNET_HELPER_send ( helper, &msg->header, GNUNET_NO, &clear_msg, - tbc); // ); + tbc); - if (NULL == tbc->shandle)// [tbc->count - 1]) + if (NULL == tbc->shandle) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Send handle is NULL!\n"); diff --git a/src/testing/testing_api_cmd_netjail_stop_testsystem.c b/src/testing/testing_api_cmd_netjail_stop_testsystem.c index 4215beef6..2e42056dc 100644 --- a/src/testing/testing_api_cmd_netjail_stop_testsystem.c +++ b/src/testing/testing_api_cmd_netjail_stop_testsystem.c @@ -118,7 +118,7 @@ stop_testing_system_run (void *cls, + j + shs->known - 1], - GNUNET_NO); + GNUNET_YES); } } } diff --git a/src/testing/testing_api_cmd_send_peer_ready.c b/src/testing/testing_api_cmd_send_peer_ready.c index 5bbabce51..1a2607047 100644 --- a/src/testing/testing_api_cmd_send_peer_ready.c +++ b/src/testing/testing_api_cmd_send_peer_ready.c @@ -46,7 +46,7 @@ struct SendPeerReadyState * The message send back to the master loop. * */ - struct GNUNET_CMDS_PEER_STARTED *reply; + struct GNUNET_TESTING_CommandPeerStarted *reply; }; @@ -86,11 +86,11 @@ send_peer_ready_run (void *cls, struct GNUNET_TESTING_Interpreter *is) { struct SendPeerReadyState *sprs = cls; - struct GNUNET_CMDS_PEER_STARTED *reply; + struct GNUNET_TESTING_CommandPeerStarted *reply; size_t msg_length; - msg_length = sizeof(struct GNUNET_CMDS_PEER_STARTED); - reply = GNUNET_new (struct GNUNET_CMDS_PEER_STARTED); + msg_length = sizeof(struct GNUNET_TESTING_CommandPeerStarted); + reply = GNUNET_new (struct GNUNET_TESTING_CommandPeerStarted); reply->header.type = htons (GNUNET_MESSAGE_TYPE_CMDS_HELPER_PEER_STARTED); reply->header.size = htons ((uint16_t) msg_length); sprs->reply = reply; diff --git a/src/testing/testing_api_loop.c b/src/testing/testing_api_loop.c index 90713e45e..420e1cfcc 100644 --- a/src/testing/testing_api_loop.c +++ b/src/testing/testing_api_loop.c @@ -28,6 +28,7 @@ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_testing_ng_lib.h" +#include "gnunet_testing_barrier.h" #include "testing.h" /** @@ -36,6 +37,21 @@ */ struct GNUNET_TESTING_Interpreter { + /** + * Send handle for sending messages to netjail nodes. + */ + struct GNUNET_HELPER_SendHandle *sh; + + /** + * Array with handles of helper processes for communication with netjails. + */ + const struct GNUNET_HELPER_Handle **helper; + + /** + * Size of the array helper. + * + */ + unsigned int n_helper; /** * Function to call with the test result. @@ -52,6 +68,11 @@ struct GNUNET_TESTING_Interpreter */ struct GNUNET_TESTING_Command *commands; + /** + * Map with barriers for this loop. + */ + struct GNUNET_CONTAINER_MultiShortmap *barriers; + /** * Number of GNUNET_TESTING_Command in commands. */ @@ -84,6 +105,24 @@ struct GNUNET_TESTING_Interpreter */ enum GNUNET_GenericReturnValue result; + /** + * Is the interpreter finishing? + */ + unsigned int finishing; + +}; + +struct FreeBarrierNodeCbCls +{ + /** + * The interpreter. + */ + struct GNUNET_TESTING_Interpreter *is; + + /** + * The barrier from which the nodes are freed.. + */ + struct GNUNET_TESTING_Barrier *barrier; }; @@ -215,6 +254,7 @@ finish_test (void *cls) struct GNUNET_TESTING_Command *cmd; const char *label; + is->finishing = GNUNET_YES; is->final_task = NULL; label = is->commands[is->ip].label; if (NULL == label) @@ -448,7 +488,7 @@ GNUNET_TESTING_finished (struct GNUNET_TESTING_Command *command) } -void +struct GNUNET_TESTING_Interpreter * GNUNET_TESTING_run (struct GNUNET_TESTING_Command *commands, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_ResultCallback rc, @@ -460,6 +500,7 @@ GNUNET_TESTING_run (struct GNUNET_TESTING_Command *commands, is = GNUNET_new (struct GNUNET_TESTING_Interpreter); is->rc = rc; is->rc_cls = rc_cls; + is->barriers = GNUNET_CONTAINER_multishortmap_create (1,GNUNET_NO); /* get the number of commands */ for (i = 0; NULL != commands[i].label; i++) ; @@ -475,6 +516,8 @@ GNUNET_TESTING_run (struct GNUNET_TESTING_Command *commands, is); is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, is); + + return is; } @@ -538,6 +581,211 @@ loop_run (void *cls) mp); } +/** + * Continuation function from GNUNET_HELPER_send() + * + * @param cls closure + * @param result GNUNET_OK on success, + * GNUNET_NO if helper process died + * GNUNET_SYSERR during GNUNET_HELPER_stop + */ +static void +clear_msg (void *cls, int result) +{ + struct GNUNET_TESTING_Interpreter *is = cls; + + GNUNET_assert (NULL != is->sh); + GNUNET_free (is->sh); + is->sh = NULL; +} + +/** + * Adding a helper handle to the interpreter. + * + * @param is The interpreter. + * @param helper The helper handle. + */ +void +GNUNET_TESTING_add_netjail_helper (struct GNUNET_TESTING_Interpreter *is, + const struct GNUNET_HELPER_Handle *helper) +{ + GNUNET_array_append (is->helper, is->n_helper, helper); +} + + +/** + * Send Message to netjail nodes that a barrier can be advanced. + * + * @param is The interpreter. + * @param global_node_number The node to inform. + * @param header The message to send. + */ +void +GNUNET_TESTING_send_message_to_netjail (struct GNUNET_TESTING_Interpreter *is, + unsigned int global_node_number, + struct GNUNET_MessageHeader *header) +{ + const struct GNUNET_HELPER_Handle *helper; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "send message of type %u to locals\n", + header->type); + helper = is->helper[global_node_number - 1]; + struct GNUNET_HELPER_SendHandle *sh = GNUNET_HELPER_send ( + (struct GNUNET_HELPER_Handle *) helper, + header, + GNUNET_NO, + &clear_msg, + is); +} + + +int +free_barrier_node_cb (void *cls, + const struct GNUNET_ShortHashCode *key, + void *value) +{ + struct FreeBarrierNodeCbCls *free_barrier_node_cb_cls = cls; + struct GNUNET_TESTING_NetjailNode *node = value; + struct GNUNET_TESTING_Barrier *barrier = free_barrier_node_cb_cls->barrier; + struct GNUNET_TESTING_Interpreter *is = free_barrier_node_cb_cls->is; + + if (GNUNET_NO == is->finishing) + { + GNUNET_TESTING_send_barrier_advance (is, + barrier->name, + node->node_number); + } + GNUNET_CONTAINER_multishortmap_remove (barrier->nodes, key, node); +} + + +/** + * Finish all "barrier reached" comands attached to this barrier. + * + * @param barrier The barrier in question. + */ +void +GNUNET_TESTING_finish_attached_cmds (struct GNUNET_TESTING_Interpreter *is, + struct GNUNET_TESTING_Barrier *barrier) +{ + struct GNUNET_TESTING_Command *pos; + struct FreeBarrierNodeCbCls *free_barrier_node_cb_cls; + + while (NULL != (pos = barrier->cmds_head)) + { + if (GNUNET_NO == pos->ac->finished && GNUNET_NO == pos->asynchronous_finish) + { + GNUNET_TESTING_async_finish (pos->ac); + } + else if (GNUNET_NO == pos->ac->finished) + { + pos->asynchronous_finish = GNUNET_YES; + } + GNUNET_CONTAINER_DLL_remove (barrier->cmds_head, + barrier->cmds_tail, + pos); + GNUNET_free (pos); + } + free_barrier_node_cb_cls = GNUNET_new (struct FreeBarrierNodeCbCls); + free_barrier_node_cb_cls->barrier = barrier; + free_barrier_node_cb_cls->is = is; + GNUNET_CONTAINER_multishortmap_iterate (barrier->nodes, free_barrier_node_cb, free_barrier_node_cb_cls); + GNUNET_CONTAINER_multishortmap_destroy (barrier->nodes); + GNUNET_free (free_barrier_node_cb_cls); +} + + +int +free_barriers_cb (void *cls, + const struct GNUNET_ShortHashCode *key, + void *value) +{ + struct GNUNET_TESTING_Interpreter *is = cls; + struct GNUNET_TESTING_Barrier *barrier = value; + struct GNUNET_TESTING_Command *pos; + struct GNUNET_TESTING_NetjailNode *node; + struct FreeBarrierNodeCbCls *free_barrier_node_cb_cls; + + free_barrier_node_cb_cls = GNUNET_new (struct FreeBarrierNodeCbCls); + free_barrier_node_cb_cls->barrier = barrier; + free_barrier_node_cb_cls->is = is; + GNUNET_CONTAINER_multishortmap_iterate (barrier->nodes, free_barrier_node_cb, free_barrier_node_cb_cls); + GNUNET_CONTAINER_multishortmap_destroy (barrier->nodes); + + while (NULL != (pos = barrier->cmds_head)) + { + GNUNET_CONTAINER_DLL_remove (barrier->cmds_head, + barrier->cmds_tail, + pos); + GNUNET_free (pos); + } + GNUNET_free (barrier); +} + + +/** + * Deleting all barriers create in the context of this interpreter. + * + * @param is The interpreter. + */ +void +GNUNET_TESTING_delete_barriers (struct GNUNET_TESTING_Interpreter *is) +{ + GNUNET_CONTAINER_multishortmap_iterate (is->barriers, + free_barriers_cb, + is); + GNUNET_CONTAINER_multishortmap_destroy (is->barriers); +} + +/** + * Getting a barrier from the interpreter. + * + * @param is The interpreter. + * @param barrier_name The name of the barrier. + * @return The barrier. + */ +struct GNUNET_TESTING_Barrier * +GNUNET_TESTING_get_barrier (struct GNUNET_TESTING_Interpreter *is, + const char *barrier_name) +{ + struct GNUNET_HashCode hc; + struct GNUNET_ShortHashCode create_key; + struct GNUNET_TESTING_Barrier *barrier; + unsigned int kx; + + GNUNET_CRYPTO_hash (barrier_name, strlen(barrier_name), &hc); + memcpy (&create_key, + &hc, + sizeof (create_key)); + barrier = GNUNET_CONTAINER_multishortmap_get (is->barriers, &create_key); + //GNUNET_free (create_key); + return barrier; +} + +/** + * Add a barrier to the loop. + * + * @param is The interpreter. + * @param barrier The barrier to add. + */ +void +GNUNET_TESTING_barrier_add (struct GNUNET_TESTING_Interpreter *is, + struct GNUNET_TESTING_Barrier *barrier) +{ + struct GNUNET_HashCode hc; + struct GNUNET_ShortHashCode create_key; + + GNUNET_CRYPTO_hash (barrier->name, strlen(barrier->name), &hc); + memcpy (&create_key, + &hc, + sizeof (create_key)); + GNUNET_CONTAINER_multishortmap_put (is->barriers, + &create_key, + barrier, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); +} + int GNUNET_TESTING_main (struct GNUNET_TESTING_Command *commands, diff --git a/src/testing/testing_cmds.h b/src/testing/testing_cmds.h index c4246d51e..edc4dfe19 100644 --- a/src/testing/testing_cmds.h +++ b/src/testing/testing_cmds.h @@ -31,10 +31,62 @@ GNUNET_NETWORK_STRUCT_BEGIN +/** + * Handle for a plugin. + */ +struct Plugin +{ + /** + * Name of the shared library. + */ + char *library_name; + + /** + * Plugin API. + */ + struct GNUNET_TESTING_PluginFunctions *api; + + /** + * IP address of the specific node the helper is running for. + * + */ + char *node_ip; + + /** + * Name of the test case plugin. + * + */ + char *plugin_name; + + /** + * The number of namespaces + * + */ + char *global_n; + + /** + * The number of local nodes per namespace. + * + */ + char *local_m; + + /** + * The number of the namespace this node is in. + * + */ + char *n; + + /** + * The number of the node in the namespace. + * + */ + char *m; +}; + /** * Initialization message for gnunet-cmds-testbed to start cmd binary. */ -struct GNUNET_CMDS_HelperInit +struct GNUNET_TESTING_CommandHelperInit { /** * Type is GNUNET_MESSAGE_TYPE_CMDS_HELPER_INIT @@ -53,7 +105,7 @@ struct GNUNET_CMDS_HelperInit /** * Reply message from cmds helper process */ -struct GNUNET_CMDS_HelperReply +struct GNUNET_TESTING_CommandHelperReply { /** * Type is GNUNET_MESSAGE_TYPE_CMDS_HELPER_REPLY @@ -61,7 +113,7 @@ struct GNUNET_CMDS_HelperReply struct GNUNET_MessageHeader header; }; -struct GNUNET_CMDS_PEER_STARTED +struct GNUNET_TESTING_CommandPeerStarted { /** * Type is GNUNET_MESSAGE_TYPE_CMDS_HELPER_PEER_STARTED @@ -69,7 +121,7 @@ struct GNUNET_CMDS_PEER_STARTED struct GNUNET_MessageHeader header; }; -struct GNUNET_CMDS_ALL_PEERS_STARTED +struct GNUNET_TESTING_CommandAllPeersStarted { /** * Type is GNUNET_MESSAGE_TYPE_CMDS_HELPER_ALL_PEERS_STARTED @@ -86,7 +138,7 @@ struct GNUNET_CMDS_LOCAL_FINISHED }; -struct GNUNET_CMDS_LOCAL_TEST_PREPARED +struct GNUNET_TESTING_CommandLocalTestPrepared { /** * Type is GNUNET_MESSAGE_TYPE_CMDS_HELPER_LOCAL_TEST_PREPARED @@ -94,7 +146,7 @@ struct GNUNET_CMDS_LOCAL_TEST_PREPARED struct GNUNET_MessageHeader header; }; -struct GNUNET_CMDS_ALL_LOCAL_TESTS_PREPARED +struct GNUNET_TESTING_CommandAllLocalTestsPrepared { /** * Type is GNUNET_MESSAGE_TYPE_CMDS_HELPER_ALL_LOCAL_TESTS_PREPARED -- cgit v1.2.3