diff options
author | t3sserakt <t3ss@posteo.de> | 2021-09-13 18:25:21 +0200 |
---|---|---|
committer | t3sserakt <t3ss@posteo.de> | 2021-09-13 18:25:21 +0200 |
commit | 72d77af5270ba1dabe6fa8c45009601b44d23b7b (patch) | |
tree | 3ea58e04fdaf79befff8925086b2dbf391586d64 /src/testing | |
parent | 46e07ed8eb64ff5a7473ac51de2e39c5a8a6ab3d (diff) |
- added tng milestone 2 versions with improvements onto version 1 files , fixed smaller issues in milestone 1 versions, added version 1 to buildbot, added new testcase for testing udp backchannel
Diffstat (limited to 'src/testing')
-rw-r--r-- | src/testing/Makefile.am | 12 | ||||
-rw-r--r-- | src/testing/gnunet-cmds-helper.c | 20 | ||||
-rwxr-xr-x | src/testing/netjail_core_v2.sh | 260 | ||||
-rwxr-xr-x | src/testing/netjail_exec_v2.sh | 14 | ||||
-rwxr-xr-x | src/testing/netjail_start_v2.sh | 61 | ||||
-rwxr-xr-x | src/testing/netjail_stop_v2.sh | 59 | ||||
-rw-r--r-- | src/testing/test_testing_api_cmd_netjail.c | 10 | ||||
-rw-r--r-- | src/testing/testing.c | 381 | ||||
-rw-r--r-- | src/testing/testing_api_cmd_netjail_start_testsystem.c | 20 | ||||
-rw-r--r-- | src/testing/testing_api_cmd_netjail_start_testsystem_v2.c | 718 | ||||
-rw-r--r-- | src/testing/testing_api_cmd_netjail_start_v2.c | 229 | ||||
-rw-r--r-- | src/testing/testing_api_cmd_netjail_stop_testsystem_v2.c | 143 | ||||
-rw-r--r-- | src/testing/testing_api_cmd_netjail_stop_v2.c | 225 | ||||
-rwxr-xr-x | src/testing/topo.sh | 95 |
14 files changed, 2217 insertions, 30 deletions
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am index 038f0cb08..3e9d15986 100644 --- a/src/testing/Makefile.am +++ b/src/testing/Makefile.am @@ -45,9 +45,13 @@ libgnunettesting_la_SOURCES = \ testing_api_cmd_send_peer_ready.c \ testing_api_cmd_block_until_all_peers_started.c \ testing_api_cmd_netjail_start.c \ + testing_api_cmd_netjail_start_v2.c \ testing_api_cmd_netjail_start_testsystem.c \ + testing_api_cmd_netjail_start_testsystem_v2.c \ testing_api_cmd_netjail_stop_testsystem.c \ + testing_api_cmd_netjail_stop_testsystem_v2.c \ testing_api_cmd_netjail_stop.c \ + testing_api_cmd_netjail_stop_v2.c \ testing.c testing.h \ testing_api_cmd_system_create.c \ testing_api_cmd_system_destroy.c \ @@ -87,6 +91,7 @@ list_keys_LDADD = \ check_PROGRAMS = \ + test_testing_topology \ test_testing_api_cmd_netjail \ test_testing_hello_world \ test_testing_portreservation \ @@ -98,6 +103,7 @@ check_PROGRAMS = \ if ENABLE_TEST_RUN AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; TESTS = \ + test_testing_topology \ test_testing_api_cmd_netjail \ test_testing_hello_world \ test_testing_portreservation \ @@ -106,6 +112,12 @@ TESTS = \ test_testing_servicestartup endif +test_testing_topology_SOURCES = \ + test_testing_topology.c +test_testing_topology_LDADD = \ + libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + test_testing_api_cmd_netjail_SOURCES = \ test_testing_api_cmd_netjail.c test_testing_api_cmd_netjail_LDADD = \ diff --git a/src/testing/gnunet-cmds-helper.c b/src/testing/gnunet-cmds-helper.c index 21ea33888..8f9e77709 100644 --- a/src/testing/gnunet-cmds-helper.c +++ b/src/testing/gnunet-cmds-helper.c @@ -163,14 +163,17 @@ struct WriteContext size_t pos; }; -struct Plugin *plugin; - /** * The process handle to the testbed service static struct GNUNET_OS_Process *cmd_binary_process;*/ /** + * Plugin to dynamically load a test case. + */ +struct Plugin *plugin; + +/** * Handle to the testing system */ static struct GNUNET_TESTING_System *test_system; @@ -329,6 +332,7 @@ write_message (struct GNUNET_MessageHeader *message, size_t msg_length) static int tokenizer_cb (void *cls, const struct GNUNET_MessageHeader *message) { + struct NodeIdentifier *ni = cls; const struct GNUNET_CMDS_HelperInit *msg; struct GNUNET_CMDS_HelperReply *reply; @@ -369,14 +373,14 @@ tokenizer_cb (void *cls, const struct GNUNET_MessageHeader *message) plugin->n = ni->n; plugin->m = ni->m; - router_ip = GNUNET_malloc (strlen (ROUTER_BASE_IP) + strlen (plugin->m) + router_ip = GNUNET_malloc (strlen (ROUTER_BASE_IP) + strlen (plugin->n) + 1); strcpy (router_ip, ROUTER_BASE_IP); - strcat (router_ip, plugin->m); + strcat (router_ip, plugin->n); - node_ip = GNUNET_malloc (strlen (NODE_BASE_IP) + strlen (plugin->n) + 1); + node_ip = GNUNET_malloc (strlen (NODE_BASE_IP) + strlen (plugin->m) + 1); strcat (node_ip, NODE_BASE_IP); - strcat (node_ip, plugin->n); + strcat (node_ip, plugin->m); plugin->api->start_testcase (&write_message, router_ip, node_ip, plugin->m, plugin->n, plugin->local_m); @@ -533,8 +537,8 @@ main (int argc, char **argv) ni = GNUNET_new (struct NodeIdentifier); ni->global_n = argv[1]; ni->local_m = argv[2]; - ni->n = argv[3]; - ni->m = argv[4]; + ni->m = argv[3]; + ni->n = argv[4]; status = GNUNET_OK; if (NULL == diff --git a/src/testing/netjail_core_v2.sh b/src/testing/netjail_core_v2.sh new file mode 100755 index 000000000..ef0a54a5e --- /dev/null +++ b/src/testing/netjail_core_v2.sh @@ -0,0 +1,260 @@ +#!/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_v2.sh b/src/testing/netjail_exec_v2.sh new file mode 100755 index 000000000..597baad20 --- /dev/null +++ b/src/testing/netjail_exec_v2.sh @@ -0,0 +1,14 @@ +#!/bin/sh +. "./../testing/netjail_core_v2.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_v2.sh b/src/testing/netjail_start_v2.sh new file mode 100755 index 000000000..cf1fe113a --- /dev/null +++ b/src/testing/netjail_start_v2.sh @@ -0,0 +1,61 @@ +#!/bin/bash +. "./../testing/netjail_core_v2.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 +done diff --git a/src/testing/netjail_stop_v2.sh b/src/testing/netjail_stop_v2.sh new file mode 100755 index 000000000..6e9fd1ccc --- /dev/null +++ b/src/testing/netjail_stop_v2.sh @@ -0,0 +1,59 @@ +#!/bin/bash +. "./../testing/netjail_core_v2.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/test_testing_api_cmd_netjail.c b/src/testing/test_testing_api_cmd_netjail.c index 543642109..aeddfb7c9 100644 --- a/src/testing/test_testing_api_cmd_netjail.c +++ b/src/testing/test_testing_api_cmd_netjail.c @@ -29,6 +29,13 @@ /** + * Return value of the test. + * + */ +static unsigned int rv = 0; + + +/** * Main function to run the test cases. * * @param cls not used. @@ -44,7 +51,8 @@ run (void *cls) GNUNET_TESTING_cmd_netjail_start_testing_system ("netjail-start-testbed-1", "2", "2", - "libgnunet_plugin_testcmd"), + "libgnunet_plugin_testcmd", + &rv), GNUNET_TESTING_cmd_stop_testing_system ("stop-testbed", "netjail-start-testbed-1", "2", diff --git a/src/testing/testing.c b/src/testing/testing.c index 991c11a6c..fcde39901 100644 --- a/src/testing/testing.c +++ b/src/testing/testing.c @@ -33,6 +33,7 @@ #include "gnunet_util_lib.h" #include "gnunet_arm_service.h" #include "gnunet_testing_lib.h" +#include "gnunet_testing_ng_lib.h" #define LOG(kind, ...) GNUNET_log_from (kind, "testing-api", __VA_ARGS__) @@ -1308,7 +1309,7 @@ GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system, peer->nports = nports; return peer; -err_ret: + err_ret: GNUNET_free (ss_instances); GNUNET_free (ports); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_); @@ -1773,4 +1774,382 @@ GNUNET_TESTING_get_testname_from_underscore (const char *argv0) } +static unsigned int +get_first_value (char *line) +{ + char *copy; + size_t slen; + char *token; + unsigned int ret; + char *rest = NULL; + + slen = strlen (line) + 1; + copy = malloc (slen); + memcpy (copy, line, slen); + token = strtok_r (copy, ":", &rest); + token = strtok_r (NULL, ":", &rest); + sscanf (token, "%u", &ret); + free (copy); + return ret; +} + + +static char * +get_key (char *line) +{ + char *copy; + size_t slen; + char *token; + char *ret; + char *rest = NULL; + + slen = strlen (line) + 1; + copy = malloc (slen); + memcpy (copy, line, slen); + token = strtok_r (copy, ":", &rest); + ret = malloc (2); + memcpy (ret, token, 2); + free (copy); + return ret; +} + + +static char * +get_first_string_value (char *line) +{ + char *copy; + size_t slen, slen_token; + char *token; + char *ret; + char *rest = NULL; + + slen = strlen (line) + 1; + copy = malloc (slen); + memcpy (copy, line, slen); + token = strtok_r (copy, ":", &rest); + token = strtok_r (NULL, ":", &rest); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "first token %s\n", + token); + slen_token = strlen (token); + ret = malloc (slen_token + 1); + memcpy (ret, token, slen_token + 1); + free (copy); + return ret; +} + + +static unsigned int +get_second_value (char *line) +{ + char *copy; + size_t slen; + char *token; + unsigned int ret; + char *rest = NULL; + + slen = strlen (line) + 1; + copy = malloc (slen); + memcpy (copy, line, slen); + token = strtok_r (copy, ":", &rest); + token = strtok_r (NULL, ":", &rest); + token = strtok_r (NULL, ":", &rest); + sscanf (token, "%u", &ret); + free (copy); + return ret; +} + + +static char * +get_value (char *key, char *line) +{ + char *copy; + size_t slen, slen_token; + char *token; + char *token2; + char *temp; + char *rest = NULL; + char *ret; + + slen = strlen (line) + 1; + copy = malloc (slen); + memcpy (copy, line, slen); + temp = strstr (copy, key); + if (NULL == temp) + return NULL; + token = strtok_r (temp, ":", &rest); + token = strtok_r (NULL, ":", &rest); + token2 = strtok_r (token, "}", &rest); + slen_token = strlen (token2); + ret = malloc (slen_token + 1); + memcpy (ret, token2, slen_token + 1); + free (copy); + return ret; +} + + +/** + * Getting the topology from file. + * + * @param filename The name of the topology file. + * @return The GNUNET_TESTING_NetjailTopology + */ +struct GNUNET_TESTING_NetjailTopology * +GNUNET_TESTING_get_topo_from_file (const char *filename) +{ + uint64_t fs; + char *data; + char *token; + char *key; + unsigned int out; + char *rest = NULL; + char *value; + int ret; + struct GNUNET_TESTING_NetjailTopology *topo = GNUNET_new (struct + GNUNET_TESTING_NetjailTopology); + struct GNUNET_TESTING_NetjailNode *node; + struct GNUNET_TESTING_NetjailRouter *router; + struct GNUNET_TESTING_NetjailNamespace *namespace; + struct GNUNET_ShortHashCode *hkey; + struct GNUNET_HashCode hc; + topo->map_namespaces = + GNUNET_CONTAINER_multishortmap_create (1,GNUNET_NO); + topo->map_globals = + GNUNET_CONTAINER_multishortmap_create (1,GNUNET_NO); + + if (GNUNET_YES != GNUNET_DISK_file_test (filename)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _ ("Topology file %s not found\n"), + filename); + return NULL; + } + if (GNUNET_OK != + GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _ ("Topology file %s has no data\n"), + filename); + return NULL; + } + data = GNUNET_malloc (fs); + if (fs != GNUNET_DISK_fn_read (filename, data, fs)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _ ("Topology file %s cannot be read\n"), + filename); + GNUNET_free (data); + return NULL; + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "data: %s\n", + data); + + token = strtok_r (data, "\n", &rest); + + while (NULL != token) + { + key = get_key (token); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "In the loop with token: %s beginning with %s\n", + token, + key); + if (0 == strcmp (key, "M")) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Get first Value for M.\n"); + out = get_first_value (token); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "M: %u\n", + out); + topo->nodes_m = out; + } + else if (0 == strcmp (key, "N")) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Get first Value for N.\n"); + out = get_first_value (token); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "N: %u\n", + out); + topo->namespaces_n = out; + } + else if (0 == strcmp (key, "X")) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Get first Value for X.\n"); + out = get_first_value (token); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "X: %u\n", + out); + topo->nodes_x = out; + } + else if (0 == strcmp (key, "T")) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Get first string value for T.\n"); + value = get_first_string_value (token); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "value: %s\n", + value); + topo->plugin = value; + } + else if (0 == strcmp (key, "K")) + { + hkey = GNUNET_new (struct GNUNET_ShortHashCode); + node = GNUNET_new (struct GNUNET_TESTING_NetjailNode); + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Get first Value for K.\n"); + out = get_first_value (token); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "K: %u\n", + out); + node->node_n = out; + GNUNET_CRYPTO_hash (&out, sizeof(out), &hc); + memcpy (hkey, + &hc, + sizeof (*hkey)); + node->is_global = GNUNET_YES; + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Get value for key value on K.\n"); + value = get_value ("plugin", token); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "value: %s\n", + value); + if (0 == GNUNET_CONTAINER_multishortmap_contains (topo->map_globals, + hkey)) + GNUNET_break (0); + else + GNUNET_CONTAINER_multishortmap_put (topo->map_globals, + hkey, + node, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + } + else if (0 == strcmp (key, "R")) + { + hkey = GNUNET_new (struct GNUNET_ShortHashCode); + router = GNUNET_new (struct GNUNET_TESTING_NetjailRouter); + node = GNUNET_new (struct GNUNET_TESTING_NetjailNode); + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Get first Value for R.\n"); + out = get_first_value (token); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "R: %u\n", + out); + node->node_n = out; + GNUNET_CRYPTO_hash (&out, sizeof(out), &hc); + memcpy (hkey, + &hc, + sizeof (*hkey)); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Get value for key tcp_port on R.\n"); + value = get_value ("tcp_port", token); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "tcp_port: %s\n", + value); + ret = sscanf (value, "%u", &(router->tcp_port)); + + GNUNET_break (0 == ret || 1 < router->tcp_port); + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Get value for key udp_port on R.\n"); + value = get_value ("udp_port", token); + ret = sscanf (value, "%u", &(router->udp_port)); + GNUNET_break (0 == ret || 1 < router->udp_port); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "udp_port: %s\n", + value); + + if (0 == GNUNET_CONTAINER_multishortmap_contains (topo->map_namespaces, + hkey)) + { + namespace = GNUNET_CONTAINER_multishortmap_get (topo->map_namespaces, + hkey); + } + else + { + namespace = GNUNET_new (struct GNUNET_TESTING_NetjailNamespace); + namespace->namespace_n = out; + GNUNET_CONTAINER_multishortmap_put (topo->map_namespaces, + hkey, + namespace, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + } + namespace->router = router; + + } + else if (0 == strcmp (key, "P")) + { + hkey = GNUNET_new (struct GNUNET_ShortHashCode); + node = GNUNET_new (struct GNUNET_TESTING_NetjailNode); + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Get first Value for P.\n"); + out = get_first_value (token); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "P: %u\n", + out); + GNUNET_CRYPTO_hash (&out, sizeof(out), &hc); + memcpy (hkey, + &hc, + sizeof (*hkey)); + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Get value for key plugin on P.\n"); + value = get_value ("plugin", token); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "plugin: %s\n", + value); + if (0 == GNUNET_CONTAINER_multishortmap_contains (topo->map_namespaces, + hkey)) + { + namespace = GNUNET_CONTAINER_multishortmap_get (topo->map_namespaces, + hkey); + } + else + { + namespace = GNUNET_new (struct GNUNET_TESTING_NetjailNamespace); + namespace->namespace_n = out; + GNUNET_CONTAINER_multishortmap_put (topo->map_namespaces, + hkey, + namespace, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Get second Value for P.\n"); + out = get_second_value (token); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "P: %u\n", + out); + GNUNET_CRYPTO_hash (&out, sizeof(out), &hc); + memcpy (hkey, + &hc, + sizeof (*hkey)); + if (0 == GNUNET_CONTAINER_multishortmap_contains (namespace->nodes, + hkey)) + { + GNUNET_break (0); + } + else + { + node = GNUNET_new (struct GNUNET_TESTING_NetjailNode); + GNUNET_CONTAINER_multishortmap_put (namespace->nodes, + hkey, + node, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + node->plugin = value; + node->node_n = out; + node->namespace_n = namespace->namespace_n; + } + } + token = strtok_r (NULL, "\n", &rest); + } + + return topo; +} + + /* end of testing.c */ diff --git a/src/testing/testing_api_cmd_netjail_start_testsystem.c b/src/testing/testing_api_cmd_netjail_start_testsystem.c index 0fe0541b0..531621eb5 100644 --- a/src/testing/testing_api_cmd_netjail_start_testsystem.c +++ b/src/testing/testing_api_cmd_netjail_start_testsystem.c @@ -278,26 +278,6 @@ GNUNET_TESTING_get_trait_helper_handles (const struct /** - * Offer messages received via testing cmd helper from trait - * - * @param cmd command to extract the message from. - * @param pt pointer to message. - * @return #GNUNET_OK on success. - */ -int -GNUNET_TESTING_get_trait_helper_messages (const struct - GNUNET_TESTING_Command *cmd, - struct HelperMessage *** - hp_messages_head) -{ - return cmd->traits (cmd->cls, - (const void **) hp_messages_head, - "hp_msgs_head", - (unsigned int) 1); -} - - -/** * Continuation function from GNUNET_HELPER_send() * * @param cls closure diff --git a/src/testing/testing_api_cmd_netjail_start_testsystem_v2.c b/src/testing/testing_api_cmd_netjail_start_testsystem_v2.c new file mode 100644 index 000000000..64ce549a4 --- /dev/null +++ b/src/testing/testing_api_cmd_netjail_start_testsystem_v2.c @@ -0,0 +1,718 @@ +/* + This file is part of GNUnet + Copyright (C) 2021 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 <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + */ + +/** + * @file testing/testing_api_cmd_hello_world.c + * @brief Command to start the netjail peers. + * @author t3sserakt + */ +#include "platform.h" +#include "gnunet_testing_ng_lib.h" +#include "testing_cmds.h" + +#define NETJAIL_EXEC_SCRIPT "./../testing/netjail_exec_v2.sh" + +/** + * Struct to store messages send/received by the helper into a DLL + * + */ +struct HelperMessage +{ + + /** + * Kept in a DLL. + */ + struct HelperMessage *next; + + /** + * Kept in a DLL. + */ + struct HelperMessage *prev; + + /** + * Size of the original message. + */ + uint16_t bytes_msg; + + /* Followed by @e bytes_msg of msg.*/ +}; + + +/** + * Struct to store information handed over to callbacks. + * + */ +struct NetJailState +{ + /** + * The complete topology infomation. + */ + struct GNUNET_TESTING_NetjailTopology *topology; + + /** + * Pointer to the return value of the test. + * + */ + unsigned int *rv; + + /** + * Head of the DLL which stores messages received by the helper. + * + */ + struct HelperMessage *hp_messages_head; + + /** + * Tail of the DLL which stores messages received by the helper. + * + */ + struct HelperMessage *hp_messages_tail; + + /** + * Array with handles of helper processes. + */ + struct GNUNET_HELPER_Handle **helper; + + /** + * Size of the array NetJailState#helper. + * + */ + unsigned int n_helper; + + /** + * Number of nodes in a natted subnet. + * + */ + unsigned int local_m; + + /** + * Number of natted subnets. + * + */ + unsigned int global_n; + + /** + * Number of global known nodes. + * + */ + unsigned int known; + + /** + * The send handle for the helper + */ + struct GNUNET_HELPER_SendHandle **shandle; + + /** + * Size of the array NetJailState#shandle. + * + */ + unsigned int n_shandle; + + /** + * The messages send to the helper. + */ + struct GNUNET_MessageHeader **msg; + + /** + * Size of the array NetJailState#msg. + * + */ + unsigned int n_msg; + + /** + * Number of test environments started. + * + */ + unsigned int number_of_testsystems_started; + + /** + * Number of peers started. + * + */ + unsigned int number_of_peers_started; + + /** + * Number of local tests finished. + * + */ + unsigned int number_of_local_test_finished; + + /** + * Name of the test case plugin the helper will load. + * + */ + char *plugin_name; + + /** + * HEAD of the DLL containing TestingSystemCount. + * + */ + struct TestingSystemCount *tbcs_head; + + /** + * TAIL of the DLL containing TestingSystemCount. + * + */ + struct TestingSystemCount *tbcs_tail; +}; + +/** + * Struct containing the number of the test environment and the NetJailState which + * will be handed to callbacks specific to a test environment. + */ +struct TestingSystemCount +{ + /** + * Kept in a DLL. + */ + struct TestingSystemCount *next; + + /** + * Kept in a DLL. + */ + struct TestingSystemCount *prev; + + /** + * The number of the test environment. + * + */ + unsigned int count; + + /** + * Struct to store information handed over to callbacks. + * + */ + struct NetJailState *ns; +}; + +/** +* Code to clean up resource this cmd used. +* +* @param cls closure +* @param cmd current CMD being cleaned up. +*/ +static void +netjail_exec_cleanup (void *cls, + const struct GNUNET_TESTING_Command *cmd) +{ + struct NetJailState *ns = cls; + struct HelperMessage *message_pos; + struct TestingSystemCount *tbc_pos; + + while (NULL != (message_pos = ns->hp_messages_head)) + { + GNUNET_CONTAINER_DLL_remove (ns->hp_messages_head, + ns->hp_messages_tail, + message_pos); + GNUNET_free (message_pos); + } + while (NULL != (tbc_pos = ns->tbcs_head)) + { + GNUNET_CONTAINER_DLL_remove (ns->tbcs_head, + ns->tbcs_tail, + tbc_pos); + GNUNET_free (tbc_pos); + } + GNUNET_free (ns); +} + + +/** + * This function prepares an array with traits. + * + */ +static int +netjail_exec_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct NetJailState *ns = cls; + struct GNUNET_HELPER_Handle **helper = ns->helper; + struct HelperMessage *hp_messages_head = ns->hp_messages_head; + + + struct GNUNET_TESTING_Trait traits[] = { + { + .index = 0, + .trait_name = "helper_handles", + .ptr = (const void *) helper, + }, + { + .index = 1, + .trait_name = "hp_msgs_head", + .ptr = (const void *) hp_messages_head, + }, + GNUNET_TESTING_trait_end () + }; + + return GNUNET_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Offer handles to testing cmd helper from trait + * + * @param cmd command to extract the message from. + * @param pt pointer to message. + * @return #GNUNET_OK on success. + */ +int +GNUNET_TESTING_get_trait_helper_handles_v2 (const struct + GNUNET_TESTING_Command *cmd, + struct GNUNET_HELPER_Handle *** + helper) +{ + return cmd->traits (cmd->cls, + (const void **) helper, + "helper_handles", + (unsigned int) 0); +} + + +/** + * 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 TestingSystemCount *tbc = cls; + struct NetJailState *ns = tbc->ns; + + GNUNET_assert (NULL != ns->shandle[tbc->count - 1]); + ns->shandle[tbc->count - 1] = NULL; + GNUNET_free (ns->msg[tbc->count - 1]); + ns->msg[tbc->count - 1] = NULL; +} + + +/** + * Functions with this signature are called whenever a + * complete message is received by the tokenizer. + * + * Do not call GNUNET_SERVER_mst_destroy in callback + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + * + * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing + */ +static int +helper_mst (void *cls, const struct GNUNET_MessageHeader *message) +{ + struct TestingSystemCount *tbc = cls; + struct NetJailState *ns = tbc->ns; + struct HelperMessage *hp_msg; + + if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_REPLY == ntohs (message->type)) + { + ns->number_of_testsystems_started++; + } + else if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_PEER_STARTED == ntohs ( + message->type)) + { + ns->number_of_peers_started++; + } + else if (GNUNET_MESSAGE_TYPE_CMDS_HELPER_LOCAL_FINISHED == ntohs ( + message->type)) + { + ns->number_of_local_test_finished++; + } + else + { + hp_msg = GNUNET_new (struct HelperMessage); + hp_msg->bytes_msg = message->size; + memcpy (&hp_msg[1], message, message->size); + GNUNET_CONTAINER_DLL_insert (ns->hp_messages_head, ns->hp_messages_tail, + hp_msg); + } + + return GNUNET_OK; +} + + +/** + * Callback called if there was an exception during execution of the helper. + * + */ +static void +exp_cb (void *cls) +{ + struct NetJailState *ns = cls; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called exp_cb.\n"); + *ns->rv = 1; +} + + +/** + * Function to initialize a init message for the helper. + * + * @param m_char The actual node in a namespace. //TODO Change this to unsigned int + * @param n_char The actual namespace. //TODO Change this to unsigned int + * @param plugin_name Name of the test case plugin the helper will load. + * + */ +static struct GNUNET_CMDS_HelperInit * +create_helper_init_msg_ (const char *plugin_name) +{ + struct GNUNET_CMDS_HelperInit *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 = GNUNET_malloc (msg_size); + msg->header.size = htons (msg_size); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_CMDS_HELPER_INIT); + msg->plugin_name_size = htons (plugin_name_len); + GNUNET_memcpy ((char *) &msg[1], + plugin_name, + plugin_name_len); + return msg; +} + + +/** + * Function which start a single helper process. + * + */ +static void +start_helper (struct NetJailState *ns, struct + GNUNET_CONFIGURATION_Handle *config, + unsigned int m, + unsigned int n) +{ + struct GNUNET_HELPER_Handle *helper; + struct GNUNET_CMDS_HelperInit *msg; + struct TestingSystemCount *tbc; + char *m_char, *n_char, *global_n_char, *local_m_char, *known_char, *node_id, + *plugin; + pid_t pid; + unsigned int script_num; + struct GNUNET_ShortHashCode *hkey; + struct GNUNET_HashCode hc; + struct GNUNET_TESTING_NetjailTopology *topology = ns->topology; + struct GNUNET_TESTING_NetjailNode *node; + struct GNUNET_TESTING_NetjailNamespace *namespace; + + + if (0 == m) + script_num = n - 1; + else + script_num = n - 1 + (n - 1) * ns->local_m + m + ns->known; + pid = getpid (); + + GNUNET_asprintf (&m_char, "%u", m); + GNUNET_asprintf (&n_char, "%u", n); + GNUNET_asprintf (&local_m_char, "%u", ns->local_m); + GNUNET_asprintf (&global_n_char, "%u",ns->global_n); + GNUNET_asprintf (&known_char, "%u",ns->known); + GNUNET_asprintf (&node_id, "%06x-%08x\n", + pid, + script_num); + + + char *const script_argv[] = {NETJAIL_EXEC_SCRIPT, + m_char, + n_char, + GNUNET_OS_get_libexec_binary_path ( + HELPER_CMDS_BINARY), + global_n_char, + local_m_char, + node_id, + NULL}; + + unsigned int helper_check = GNUNET_OS_check_helper_binary ( + NETJAIL_EXEC_SCRIPT, + GNUNET_YES, + NULL); + + tbc = GNUNET_new (struct TestingSystemCount); + tbc->ns = ns; + if (0 == m) + tbc->count = n; + else + tbc->count = (n - 1) * ns->local_m + m + ns->known; + + GNUNET_CONTAINER_DLL_insert (ns->tbcs_head, ns->tbcs_tail, + tbc); + + + if (GNUNET_NO == helper_check) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No SUID for %s!\n", + NETJAIL_EXEC_SCRIPT); + *ns->rv = 1; + } + else if (GNUNET_NO == helper_check) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%s not found!\n", + NETJAIL_EXEC_SCRIPT); + *ns->rv = 1; + } + + GNUNET_array_append (ns->helper, ns->n_helper, GNUNET_HELPER_start ( + GNUNET_YES, + NETJAIL_EXEC_SCRIPT, + script_argv, + &helper_mst, + &exp_cb, + tbc)); + + helper = ns->helper[tbc->count - 1]; + + hkey = GNUNET_new (struct GNUNET_ShortHashCode); + + plugin = ns->plugin_name; + + if (0 == m) + { + + GNUNET_CRYPTO_hash (&n, sizeof(n), &hc); + memcpy (hkey, + &hc, + sizeof (*hkey)); + if (1 == GNUNET_CONTAINER_multishortmap_contains (topology->map_globals, + hkey)) + { + node = GNUNET_CONTAINER_multishortmap_get (topology->map_globals, + hkey); + plugin = node->plugin; + } + + } + else + { + GNUNET_CRYPTO_hash (&m, sizeof(m), &hc); + memcpy (hkey, + &hc, + sizeof (*hkey)); + if (1 == GNUNET_CONTAINER_multishortmap_contains (topology->map_namespaces, + hkey)) + { + namespace = GNUNET_CONTAINER_multishortmap_get (topology->map_namespaces, + hkey); + GNUNET_CRYPTO_hash (&n, sizeof(n), &hc); + memcpy (hkey, + &hc, + sizeof (*hkey)); + if (1 == GNUNET_CONTAINER_multishortmap_contains (namespace->nodes, + hkey)) + { + node = GNUNET_CONTAINER_multishortmap_get (namespace->nodes, + hkey); + plugin = node->plugin; + } + } + + + } + + msg = create_helper_init_msg_ (plugin); + + GNUNET_array_append (ns->msg, ns->n_msg, &msg->header); + + GNUNET_array_append (ns->shandle, ns->n_shandle, GNUNET_HELPER_send ( + helper, + &msg->header, + GNUNET_NO, + &clear_msg, + tbc)); + + if (NULL == ns->shandle[tbc->count - 1]) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Send handle is NULL!\n"); + GNUNET_free (msg); + *ns->rv = 1; + } +} + + +/** +* This function starts a helper process for each node. +* +* @param cls closure. +* @param cmd CMD being run. +* @param is interpreter state. +*/ +static void +netjail_exec_run (void *cls, + const struct GNUNET_TESTING_Command *cmd, + struct GNUNET_TESTING_Interpreter *is) +{ + struct NetJailState *ns = cls; + struct GNUNET_CONFIGURATION_Handle *config = + GNUNET_CONFIGURATION_create (); + + for (int i = 1; i <= ns->known; i++) + { + start_helper (ns, config, + i, + 0); + } + + for (int i = 1; i <= ns->global_n; i++) + { + for (int j = 1; j <= ns->local_m; j++) + { + start_helper (ns, config, + j, + i); + } + } +} + + +static void +send_all_peers_started (unsigned int i, unsigned int j, struct NetJailState *ns) +{ + unsigned int total_number = ns->local_m * ns->global_n + ns->known; + struct GNUNET_CMDS_ALL_PEERS_STARTED *reply; + size_t msg_length; + struct GNUNET_HELPER_Handle *helper; + struct TestingSystemCount *tbc; + + 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; + else + tbc->count = (i - 1) * ns->local_m + j + total_number + ns->known; + + helper = ns->helper[tbc->count - 1 - total_number]; + msg_length = sizeof(struct GNUNET_CMDS_ALL_PEERS_STARTED); + reply = GNUNET_new (struct GNUNET_CMDS_ALL_PEERS_STARTED); + reply->header.type = htons ( + GNUNET_MESSAGE_TYPE_CMDS_HELPER_ALL_PEERS_STARTED); + reply->header.size = htons ((uint16_t) msg_length); + + GNUNET_array_append (ns->msg, ns->n_msg, &reply->header); + + struct GNUNET_HELPER_SendHandle *sh = GNUNET_HELPER_send ( + helper, + &reply->header, + GNUNET_NO, + &clear_msg, + tbc); + + GNUNET_array_append (ns->shandle, ns->n_shandle, sh); +} + + +/** + * This function checks on three different information. + * + * 1. Did all helpers start. This is only logged. + * 2. Did all peer start. + * In this case a GNUNET_MESSAGE_TYPE_CMDS_HELPER_ALL_PEERS_STARTED is send to all peers. + * 3. Did all peers finished the test case. In this case interpreter_next will be called. + * + */ +static int +netjail_start_finish (void *cls, + GNUNET_SCHEDULER_TaskCallback cont, + void *cont_cls) +{ + unsigned int ret = GNUNET_NO; + struct NetJailState *ns = cls; + unsigned int total_number = ns->local_m * ns->global_n + ns->known; + + + if (ns->number_of_local_test_finished == total_number) + { + ret = GNUNET_YES; + cont (cont_cls); + } + + if (ns->number_of_testsystems_started == total_number) + { + ns->number_of_testsystems_started = 0; + } + + 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++) + { + for (int j = 1; j <= ns->local_m; j++) + { + send_all_peers_started (i,j, ns); + } + } + ns->number_of_peers_started = 0; + } + return ret; +} + + +/** + * Create command. + * + * @param label Name for the command. + * @param topology_config Configuration file for the test topology. + * @param rv Pointer to the return value of the test. + * @return command. + */ +struct GNUNET_TESTING_Command +GNUNET_TESTING_cmd_netjail_start_testing_system_v2 (const char *label, + const char *topology_config, + unsigned int *rv) +{ + struct NetJailState *ns; + + struct GNUNET_TESTING_NetjailTopology *topology = + GNUNET_TESTING_get_topo_from_file (topology_config); + + ns = GNUNET_new (struct NetJailState); + ns->rv = rv; + ns->local_m = topology->nodes_m; + ns->global_n = topology->namespaces_n; + ns->known = topology->nodes_x; + ns->plugin_name = topology->plugin; + ns->topology = topology; + + struct GNUNET_TESTING_Command cmd = { + .cls = ns, + .label = label, + .run = &netjail_exec_run, + .finish = &netjail_start_finish, + .cleanup = &netjail_exec_cleanup, + .traits = &netjail_exec_traits + }; + + return cmd; +} diff --git a/src/testing/testing_api_cmd_netjail_start_v2.c b/src/testing/testing_api_cmd_netjail_start_v2.c new file mode 100644 index 000000000..36fbb0e10 --- /dev/null +++ b/src/testing/testing_api_cmd_netjail_start_v2.c @@ -0,0 +1,229 @@ +/* + This file is part of GNUnet + Copyright (C) 2021 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 <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + */ + +/** + * @file testing/testing_api_cmd_hello_world.c + * @brief Command to start the netjail script. + * @author t3sserakt + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_testing_ng_lib.h" + +#define NETJAIL_START_SCRIPT "./../testing/netjail_start_v2.sh" + +/** + * Struct to hold information for callbacks. + * + */ +struct NetJailState +{ + // Child Wait handle + struct GNUNET_ChildWaitHandle *cwh; + + /** + * Configuration file for the test topology. + */ + char *topology_config; + + /** + * The process id of the start script. + */ + struct GNUNET_OS_Process *start_proc; + + // Flag indication if the script finished. + unsigned int finished; +}; + + +/** + * The cleanup function of this cmd frees resources the cmd allocated. + * + */ +static void +netjail_start_cleanup (void *cls, + const struct GNUNET_TESTING_Command *cmd) +{ + struct NetJailState *ns = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "netjail_start_cleanup!\n"); + + if (NULL != ns->cwh) + { + GNUNET_wait_child_cancel (ns->cwh); + ns->cwh = NULL; + } + if (NULL != ns->start_proc) + { + GNUNET_assert (0 == + GNUNET_OS_process_kill (ns->start_proc, + SIGKILL)); + GNUNET_assert (GNUNET_OK == + GNUNET_OS_process_wait (ns->start_proc)); + GNUNET_OS_process_destroy (ns->start_proc); + ns->start_proc = NULL; + } + GNUNET_free (ns); +} + + +/** + * Trait function of this cmd does nothing. + * + */ +static int +netjail_start_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + return GNUNET_OK; +} + + +/** + * Callback which will be called if the setup script finished. + * + */ +static void +child_completed_callback (void *cls, + enum GNUNET_OS_ProcessStatusType type, + long unsigned int exit_code) +{ + struct NetJailState *ns = cls; + + if (0 == exit_code) + { + ns->finished = GNUNET_YES; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Child completed with an error!\n"); + ns->finished = GNUNET_SYSERR; + } + GNUNET_OS_process_destroy (ns->start_proc); + ns->start_proc = NULL; +} + + + +/** +* The run method starts the script which setup the network namespaces. +* +* @param cls closure. +* @param cmd CMD being run. +* @param is interpreter state. +*/ +static void +netjail_start_run (void *cls, + const struct GNUNET_TESTING_Command *cmd, + struct GNUNET_TESTING_Interpreter *is) +{ + struct NetJailState *ns = cls; + char *pid; + GNUNET_asprintf (&pid, + "%u", + getpid ()); + char *const script_argv[] = {NETJAIL_START_SCRIPT, + ns->topology_config, + pid, + NULL}; + unsigned int helper_check = GNUNET_OS_check_helper_binary ( + NETJAIL_START_SCRIPT, + GNUNET_YES, + NULL); + + if (GNUNET_NO == helper_check) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No SUID for %s!\n", + NETJAIL_START_SCRIPT); + GNUNET_TESTING_interpreter_fail (); + } + else if (GNUNET_NO == helper_check) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%s not found!\n", + NETJAIL_START_SCRIPT); + GNUNET_TESTING_interpreter_fail (); + } + + ns->start_proc = GNUNET_OS_start_process_vap (GNUNET_OS_INHERIT_STD_ERR, + NULL, + NULL, + NULL, + NETJAIL_START_SCRIPT, + script_argv); + + ns->cwh = GNUNET_wait_child (ns->start_proc, + &child_completed_callback, + ns); + GNUNET_break (NULL != ns->cwh); +} + + +/** + * This function checks the flag NetJailState#finished, if this cmd finished. + * + */ +static int +netjail_start_finish (void *cls, + GNUNET_SCHEDULER_TaskCallback cont, + void *cont_cls) +{ + struct NetJailState *ns = cls; + + if (ns->finished) + { + cont (cont_cls); + } + return ns->finished; +} + +/** + * Create command. + * + * @param label name for command. + * @param topology_config Configuration file for the test topology. + * @return command. + */ +struct GNUNET_TESTING_Command +GNUNET_TESTING_cmd_netjail_start_v2 (const char *label, + char *topology_config) +{ + struct NetJailState *ns; + + ns = GNUNET_new (struct NetJailState); + ns->finished = GNUNET_NO; + ns->topology_config = topology_config; + + struct GNUNET_TESTING_Command cmd = { + .cls = ns, + .label = label, + .run = &netjail_start_run, + .finish = &netjail_start_finish, + .cleanup = &netjail_start_cleanup, + .traits = &netjail_start_traits + }; + + return cmd; +} diff --git a/src/testing/testing_api_cmd_netjail_stop_testsystem_v2.c b/src/testing/testing_api_cmd_netjail_stop_testsystem_v2.c new file mode 100644 index 000000000..8eccc5764 --- /dev/null +++ b/src/testing/testing_api_cmd_netjail_stop_testsystem_v2.c @@ -0,0 +1,143 @@ +/* + This file is part of GNUnet + Copyright (C) 2021 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 <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + */ + +/** + * @file testing/testing_api_cmd_hello_world.c + * @brief Command to start the netjail peers. + * @author t3sserakt + */ +#include "platform.h" +#include "gnunet_testing_ng_lib.h" +#include "testing_cmds.h" + + +/** + * Struct to store information handed over to callbacks. + * + */ +struct StopHelperState +{ + + const char *helper_start_label; + + /** + * The process handle + */ + struct GNUNET_HELPER_Handle **helper; + + unsigned int local_m; + + unsigned int global_n; +}; + + +/** +* Code to clean up resource this cmd used. +* +* @param cls closure +* @param cmd current CMD being cleaned up. +*/ +static void +stop_testing_system_cleanup (void *cls, + const struct GNUNET_TESTING_Command *cmd) +{ + +} + + +/** + * Trait function of this cmd does nothing. + * + */ +static int +stop_testing_system_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + return GNUNET_OK; +} + + +/** +* This function stops the helper process for each node. +* +* @param cls closure. +* @param cmd CMD being run. +* @param is interpreter state. +*/ +static void +stop_testing_system_run (void *cls, + const struct GNUNET_TESTING_Command *cmd, + struct GNUNET_TESTING_Interpreter *is) +{ + struct StopHelperState *shs = cls; + struct GNUNET_HELPER_Handle **helper; + const struct GNUNET_TESTING_Command *start_helper_cmd; + + start_helper_cmd = GNUNET_TESTING_interpreter_lookup_command ( + shs->helper_start_label); + GNUNET_TESTING_get_trait_helper_handles (start_helper_cmd, + &helper); + + for (int i = 1; i <= shs->global_n; i++) + { + for (int j = 1; j <= shs->local_m; j++) + { + GNUNET_HELPER_stop (helper[(i - 1) * shs->local_m + j - 1], + GNUNET_YES); + } + } +} + + +/** + * Create command. + * + * @param label name for command. + * @param helper_start_label label of the cmd to start the test system. + * @param topology_config Configuration file for the test topology. + * @return command. + */ +struct GNUNET_TESTING_Command +GNUNET_TESTING_cmd_stop_testing_system_v2 (const char *label, + const char *helper_start_label, + const char *topology_config) +{ + struct StopHelperState *shs; + + struct GNUNET_TESTING_NetjailTopology *topology = + GNUNET_TESTING_get_topo_from_file (topology_config); + + shs = GNUNET_new (struct StopHelperState); + shs->helper_start_label = helper_start_label; + shs->local_m = topology->nodes_m; + shs->global_n = topology->namespaces_n; + + struct GNUNET_TESTING_Command cmd = { + .cls = shs, + .label = label, + .run = &stop_testing_system_run, + .cleanup = &stop_testing_system_cleanup, + .traits = &stop_testing_system_traits + }; + + return cmd; +} diff --git a/src/testing/testing_api_cmd_netjail_stop_v2.c b/src/testing/testing_api_cmd_netjail_stop_v2.c new file mode 100644 index 000000000..1d13407d7 --- /dev/null +++ b/src/testing/testing_api_cmd_netjail_stop_v2.c @@ -0,0 +1,225 @@ +/* + This file is part of GNUnet + Copyright (C) 2021 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 <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + */ + +/** + * @file testing/testing_api_cmd_hello_world.c + * @brief Command to stop the netjail script. + * @author t3sserakt + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_testing_ng_lib.h" + + +#define NETJAIL_STOP_SCRIPT "./../testing/netjail_stop_v2.sh" + +// Child Wait handle +struct GNUNET_ChildWaitHandle *cwh; + +/** + * Struct to hold information for callbacks. + * + */ +struct NetJailState +{ + /** + * Configuration file for the test topology. + */ + char *topology_config; + + /** + * The process id of the start script. + */ + struct GNUNET_OS_Process *stop_proc; + + // Flag indication if the script finished. + unsigned int finished; +}; + + +/** + * The cleanup function of this cmd frees resources the cmd allocated. + * + */ +static void +netjail_stop_cleanup (void *cls, + const struct GNUNET_TESTING_Command *cmd) +{ + struct NetJailState *ns = cls; + + if (NULL != cwh) + { + GNUNET_wait_child_cancel (cwh); + cwh = NULL; + } + if (NULL != ns->stop_proc) + { + GNUNET_assert (0 == + GNUNET_OS_process_kill (ns->stop_proc, + SIGKILL)); + GNUNET_assert (GNUNET_OK == + GNUNET_OS_process_wait (ns->stop_proc)); + GNUNET_OS_process_destroy (ns->stop_proc); + ns->stop_proc = NULL; + } +} + + +/** + * Trait function of this cmd does nothing. + * + */ +static int +netjail_stop_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + return GNUNET_OK; +} + + +/** + * Callback which will be called if the setup script finished. + * + */ +static void +child_completed_callback (void *cls, + enum GNUNET_OS_ProcessStatusType type, + long unsigned int exit_code) +{ + struct NetJailState *ns = cls; + + cwh = NULL; + if (0 == exit_code) + { + ns->finished = GNUNET_YES; + } + else + { + ns->finished = GNUNET_SYSERR; + } + GNUNET_OS_process_destroy (ns->stop_proc); + ns->stop_proc = NULL; +} + + +/** +* The run method starts the script which deletes the network namespaces. +* +* @param cls closure. +* @param cmd CMD being run. +* @param is interpreter state. +*/ +static void +netjail_stop_run (void *cls, + const struct GNUNET_TESTING_Command *cmd, + struct GNUNET_TESTING_Interpreter *is) +{ + struct NetJailState *ns = cls; + char *pid; + GNUNET_asprintf (&pid, + "%u", + getpid ()); + char *const script_argv[] = {NETJAIL_STOP_SCRIPT, + ns->topology_config, + pid, + NULL}; + unsigned int helper_check = GNUNET_OS_check_helper_binary ( + NETJAIL_STOP_SCRIPT, + GNUNET_YES, + NULL); + + if (GNUNET_NO == helper_check) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No SUID for %s!\n", + NETJAIL_STOP_SCRIPT); + GNUNET_TESTING_interpreter_fail (); + } + else if (GNUNET_NO == helper_check) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%s not found!\n", + NETJAIL_STOP_SCRIPT); + GNUNET_TESTING_interpreter_fail (); + } + + ns->stop_proc = GNUNET_OS_start_process_vap (GNUNET_OS_INHERIT_STD_ERR, + NULL, + NULL, + NULL, + NETJAIL_STOP_SCRIPT, + script_argv); + + cwh = GNUNET_wait_child (ns->stop_proc, + &child_completed_callback, + ns); + GNUNET_break (NULL != cwh); + +} + + +/** + * This function checks the flag NetJailState#finished, if this cmd finished. + * + */ +static int +netjail_stop_finish (void *cls, + GNUNET_SCHEDULER_TaskCallback cont, + void *cont_cls) +{ + struct NetJailState *ns = cls; + + if (ns->finished) + { + cont (cont_cls); + } + return ns->finished; +} + + +/** + * Create command. + * + * @param label name for command. + * @param topology_config Configuration file for the test topology. + * @return command. + */ +struct GNUNET_TESTING_Command +GNUNET_TESTING_cmd_netjail_stop_v2 (const char *label, + char *topology_config) +{ + struct NetJailState *ns; + + ns = GNUNET_new (struct NetJailState); + ns->topology_config = topology_config; + + struct GNUNET_TESTING_Command cmd = { + .cls = ns, + .label = label, + .run = &netjail_stop_run, + .finish = &netjail_stop_finish, + .cleanup = &netjail_stop_cleanup, + .traits = &netjail_stop_traits + }; + + return cmd; +} diff --git a/src/testing/topo.sh b/src/testing/topo.sh new file mode 100755 index 000000000..090c3053f --- /dev/null +++ b/src/testing/topo.sh @@ -0,0 +1,95 @@ +#!/bin/bash + +declare -A K_PLUGIN +declare -A R_TCP +declare -A R_UDP +declare -A P_PLUGIN + +extract_attributes() +{ + line_key=$1 + line=$2 + + if [ "$line_key" = "P" ] + then + n=$(echo $line|cut -d \| -f 1|awk -F: '{print $2}') + echo $n + m=$(echo $line|cut -d \| -f 1|awk -F: '{print $3}') + echo $m + else + number=$(echo $line|cut -d \| -f 1| cut -c 2-|cut -d : -f 2 ) + echo $number + fi + + + nf=$(echo $line|awk -F: '{print NF}') + for ((i=2;i<=$nf;i++)) + do + entry=$(echo $line |awk -v i=$i -F\| '{print $i}') + key=$(echo $entry|cut -d { -f 2|cut -d } -f 1|cut -d : -f 1) + value=$(echo $entry|cut -d { -f 2|cut -d } -f 1|cut -d : -f 2) + if [ "$key" = "tcp_port" ] + then + echo tcp port: $value + R_TCP[$number]=$value + elif [ "$key" = "udp_port" ] + then + echo udp port: $value + R_UDP[$number]=$value + elif [ "$key" = "plugin" ] + then + echo plugin: $value + echo $line_key + if [ "$line_key" = "P" ] + then + P_PLUGIN[$n,$m]=$value + echo $n $m ${P_PLUGIN[$n,$m]} + elif [ "$line_key" = "K" ] + then + K_PLUGIN[$number]=$value + fi + fi + done +} + +read_topology(){ + +local filename=$1 +while read line; do +# reading each line + echo $line + key=$(cut -c -1 <<< $line) + if [ "$key" = "M" ] + then + LOCAL_M=$(cut -d : -f 2 <<< $line) + echo $LOCAL_M + elif [ "$key" = "N" ] + then + GLOBAL_N=$(cut -d : -f 2 <<< $line) + echo $GLOBAL_N + elif [ "$key" = "X" ] + then + KNOWN=$(cut -d : -f 2 <<< $line) + echo $KNOWN + elif [ "$key" = "T" ] + then + PLUGIN=$(cut -d : -f 2 <<< $line) + echo $PLUGIN + elif [ "$key" = "K" ] + then + echo know node + extract_attributes $key $line + elif [ "$key" = "R" ] + then + echo router + extract_attributes $key $line + elif [ "$key" = "P" ] + then + echo node + extract_attributes $key $line + fi +done < $filename +} + + + |