gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnunet] branch master updated: - starting testbed with netjail


From: gnunet
Subject: [gnunet] branch master updated: - starting testbed with netjail
Date: Wed, 30 Jun 2021 13:26:28 +0200

This is an automated email from the git hooks/post-receive script.

t3sserakt pushed a commit to branch master
in repository gnunet.

The following commit(s) were added to refs/heads/master by this push:
     new 13dbe5418 - starting testbed with netjail
13dbe5418 is described below

commit 13dbe5418c1e61bb3c433efa7c2dc412e08b356d
Author: t3sserakt <t3ss@posteo.de>
AuthorDate: Wed Jun 30 13:04:40 2021 +0200

    - starting testbed with netjail
---
 src/include/gnunet_testbed_ng_service.h            |  39 ++++
 src/include/gnunet_testing_ng_lib.h                |   2 +-
 src/testbed/Makefile.am                            |  12 +
 src/testbed/netjail_core.sh                        | 107 +++++++++
 src/testbed/netjail_exec.sh                        |  19 ++
 src/testbed/netjail_start.sh                       |  52 +++++
 src/testbed/netjail_stop.sh                        |  26 +++
 src/testbed/test_testbed_api_cmd_netjail.c         |  94 ++++++++
 src/testbed/testbed_api_cmd_netjail_start.c        | 193 +++++++++++++++
 .../testbed_api_cmd_netjail_start_testbed.c        | 258 +++++++++++++++++++++
 src/testbed/testbed_api_cmd_netjail_stop.c         | 197 ++++++++++++++++
 src/testing/testing_api_loop.c                     |  54 +++--
 src/util/child_management.c                        |  42 ++--
 13 files changed, 1062 insertions(+), 33 deletions(-)

diff --git a/src/include/gnunet_testbed_ng_service.h 
b/src/include/gnunet_testbed_ng_service.h
index 370617e68..b19a6e958 100644
--- a/src/include/gnunet_testbed_ng_service.h
+++ b/src/include/gnunet_testbed_ng_service.h
@@ -213,4 +213,43 @@ GNUNET_TESTBED_shutdown_peer (struct PeerCmdState *ps);
 void
 GNUNET_TESTBED_shutdown_service (struct TngState *ss);
 
+/**
+ * Create command.
+ *
+ * @param label name for command.
+ * @param binaryname to start.
+ * @return command.
+ */
+struct GNUNET_TESTING_Command
+GNUNET_TESTBED_cmd_netjail_start (const char *label,
+                                  char *local_m,
+                                  char *global_n);
+
+/**
+ * Create command.
+ *
+ * @param label name for command.
+ * @param binaryname to exec.
+ * @return command.
+ */
+struct GNUNET_TESTING_Command
+GNUNET_TESTBED_cmd_netjail_start_testbed (const char *label,
+                                          char *const binary_argv[],
+                                          char *local_m,
+                                          char *global_n,
+                                          GNUNET_MessageTokenizerCallback cb,
+                                          GNUNET_HELPER_ExceptionCallback 
exp_cb);
+
+/**
+ * Create command.
+ *
+ * @param label name for command.
+ * @param binaryname to stop.
+ * @return command.
+ */
+struct GNUNET_TESTING_Command
+GNUNET_TESTBED_cmd_netjail_stop (const char *label,
+                                 char *local_m,
+                                 char *global_n);
+
 #endif
diff --git a/src/include/gnunet_testing_ng_lib.h 
b/src/include/gnunet_testing_ng_lib.h
index 55c8a7246..dd83bbe82 100644
--- a/src/include/gnunet_testing_ng_lib.h
+++ b/src/include/gnunet_testing_ng_lib.h
@@ -101,7 +101,7 @@ struct GNUNET_TESTING_Command
    * @param cont function to call upon completion, can be NULL
    * @param cont_cls closure for @a cont
    */
-  bool
+  int
   (*finish)(void *cls,
             GNUNET_SCHEDULER_TaskCallback cont,
             void *cont_cls);
diff --git a/src/testbed/Makefile.am b/src/testbed/Makefile.am
index 5b81f7295..486c4a4f8 100644
--- a/src/testbed/Makefile.am
+++ b/src/testbed/Makefile.am
@@ -92,6 +92,9 @@ lib_LTLIBRARIES = \
   libgnunettestbed.la
 
 libgnunettestbed_la_SOURCES = \
+  testbed_api_cmd_netjail_start.c \
+  testbed_api_cmd_netjail_start_testbed.c \
+  testbed_api_cmd_netjail_stop.c \
   testbed_api.c testbed_api.h testbed.h \
   testbed_api_hosts.c testbed_api_hosts.h testbed_helper.h \
   testbed_api_cmd_controller.c \
@@ -131,6 +134,7 @@ generate_underlay_topology_LDADD = $(XLIB) \
  $(LTLIBINTL) -lsqlite3
 
 check_PROGRAMS = \
+  test_testbed_api_cmd_netjail \
   test_testbed_api_hosts \
   test_gnunet_helper_testbed \
   test_testbed_api_controllerlink \
@@ -165,6 +169,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_testbed_api_cmd_netjail \
   test_testbed_api \
   test_testbed_api_sd \
   test_testbed_api_operations \
@@ -195,6 +200,13 @@ if ENABLE_TEST_RUN
   $(underlay_testcases)
 endif
 
+test_testbed_api_cmd_netjail_SOURCES = \
+ test_testbed_api_cmd_netjail.c
+test_testbed_api_cmd_netjail_LDADD = \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
 test_testbed_api_SOURCES = \
  test_testbed_api.c
 test_testbed_api_LDADD = \
diff --git a/src/testbed/netjail_core.sh b/src/testbed/netjail_core.sh
new file mode 100755
index 000000000..d25948bc7
--- /dev/null
+++ b/src/testbed/netjail_core.sh
@@ -0,0 +1,107 @@
+#!/bin/sh
+# 
+
+JAILOR=${SUDO_USER:?must run in sudo}
+
+# 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"
+
+netjail_check() {
+       NODE_COUNT=$1
+
+       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_print_name() {
+       printf "%s%02x%02x" $1 $2 ${3:-0}
+}
+
+netjail_bridge() {
+       BRIDGE=$1
+
+       ip link add $BRIDGE type bridge
+       ip link set dev $BRIDGE up
+}
+
+netjail_bridge_clear() {
+       BRIDGE=$1
+
+       ip link delete $BRIDGE
+}
+
+netjail_node() {
+       NODE=$1
+
+       ip netns add $NODE
+}
+
+netjail_node_clear() {
+       NODE=$1
+
+       ip netns delete $NODE
+}
+
+netjail_node_link_bridge() {
+       NODE=$1
+       BRIDGE=$2
+       ADDRESS=$3
+       MASK=$4
+       
+       LINK_IF="$NODE-$BRIDGE-0"
+       LINK_BR="$NODE-$BRIDGE-1"
+
+       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
+}
+
+netjail_node_add_nat() {
+       NODE=$1
+       ADDRESS=$2
+       MASK=$3
+
+       ip netns exec $NODE iptables -t nat -A POSTROUTING -s "$ADDRESS/$MASK" 
-j MASQUERADE
+}
+
+netjail_node_add_default() {
+       NODE=$1
+       ADDRESS=$2
+
+       ip -n $NODE route add default via $ADDRESS
+}
+
+netjail_node_exec() {
+       NODE=$1
+       FD_IN=$2
+       FD_OUT=$3
+       shift 3
+
+       unshare -fp --kill-child -- ip netns exec $NODE sudo -u $JAILOR -- $@ 
1>& $FD_OUT 0<& $FD_IN
+}
+
+netjail_node_exec_without_fds() {
+       local NODE=$1
+       shift 3
+
+       unshare -fp --kill-child -- ip netns exec $NODE sudo -u $JAILOR -- $@
+}
+
diff --git a/src/testbed/netjail_exec.sh b/src/testbed/netjail_exec.sh
new file mode 100755
index 000000000..274a8b037
--- /dev/null
+++ b/src/testbed/netjail_exec.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+. "./netjail_core.sh"
+
+set -eu
+set -x
+
+export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
+
+LOCAL_M=$1
+M=$2
+N=$3
+
+NODE=$(netjail_print_name "N" $N $M)
+INDEX=$(($LOCAL_M * ($N - 1) + $M - 1))
+
+FD_X=$(($INDEX * 2 + 3 + 0))
+FD_Y=$(($INDEX * 2 + 3 + 1))
+
+netjail_node_exec_without_fds $NODE $@
diff --git a/src/testbed/netjail_start.sh b/src/testbed/netjail_start.sh
new file mode 100755
index 000000000..a2abca2d7
--- /dev/null
+++ b/src/testbed/netjail_start.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+. "./netjail_core.sh"
+
+set -eu
+set -x
+
+export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
+
+LOCAL_M=$1
+GLOBAL_N=$2
+
+# TODO: stunserver? ..and globally known peer?
+
+shift 2
+
+LOCAL_GROUP="192.168.15"
+GLOBAL_GROUP="92.68.150"
+
+NETWORK_NET=$(netjail_print_name "n" $GLOBAL_N $LOCAL_M)
+
+netjail_bridge $NETWORK_NET
+
+for N in $(seq $GLOBAL_N); do
+       ROUTER=$(netjail_print_name "R" $N)
+
+       netjail_node $ROUTER 
+       netjail_node_link_bridge $ROUTER $NETWORK_NET "$GLOBAL_GROUP.$N" 24
+
+       ROUTER_NET=$(netjail_print_name "r" $N)
+
+       netjail_bridge $ROUTER_NET
+       
+       for M in $(seq $LOCAL_M); do
+               NODE=$(netjail_print_name "N" $N $M)
+
+               netjail_node $NODE
+               netjail_node_link_bridge $NODE $ROUTER_NET "$LOCAL_GROUP.$M" 24
+       done
+
+       ROUTER_ADDR="$LOCAL_GROUP.$(($LOCAL_M+1))"
+
+       netjail_node_link_bridge $ROUTER $ROUTER_NET $ROUTER_ADDR 24
+       netjail_node_add_nat $ROUTER $ROUTER_ADDR 24
+       
+       for M in $(seq $LOCAL_M); do
+               NODE=$(netjail_print_name "N" $N $M)
+               
+               netjail_node_add_default $NODE $ROUTER_ADDR
+       done
+done
+
+
diff --git a/src/testbed/netjail_stop.sh b/src/testbed/netjail_stop.sh
new file mode 100755
index 000000000..4763cb107
--- /dev/null
+++ b/src/testbed/netjail_stop.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+. "./netjail_core.sh"
+
+set -eu
+set -x
+
+export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
+
+LOCAL_M=$1
+GLOBAL_N=$2
+NETWORK_NET=$(netjail_print_name "n" $GLOBAL_N $LOCAL_M)
+
+shift 2
+
+for N in $(seq $GLOBAL_N); do
+       for M in $(seq $LOCAL_M); do
+               netjail_node_clear $(netjail_print_name "N" $N $M)
+       done
+       
+       netjail_bridge_clear $(netjail_print_name "r" $N)
+       netjail_node_clear $(netjail_print_name "R" $N)
+done
+
+netjail_bridge_clear $NETWORK_NET
+
+echo "Done"
diff --git a/src/testbed/test_testbed_api_cmd_netjail.c 
b/src/testbed/test_testbed_api_cmd_netjail.c
new file mode 100644
index 000000000..d29ebdcb4
--- /dev/null
+++ b/src/testbed/test_testbed_api_cmd_netjail.c
@@ -0,0 +1,94 @@
+/*
+      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/test_testing_api_cmd_netjail.c
+ * @brief Test case executing a script in a network name space.
+ * @author t3sserakt
+ */
+#include "platform.h"
+#include "gnunet_testing_ng_lib.h"
+#include "gnunet_testbed_ng_service.h"
+#include "gnunet_util_lib.h"
+
+#define HELPER_TESTBED_BINARY "../testbed/gnunet-helper-testbed"
+
+static int
+tokenizer_cb (void *cls, const struct GNUNET_MessageHeader *message)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called tokenizer.\n");
+  return GNUNET_OK;
+}
+
+
+static void
+exp_cb (void *cls)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called exp_cb.\n");
+}
+
+
+/**
+ * Main function to run the test cases.
+ *
+ * @param cls not used.
+ *
+ */
+static void
+run (void *cls)
+{
+  char *const binary_argv[3] = {HELPER_TESTBED_BINARY, NULL};
+
+  struct GNUNET_TESTING_Command commands[] = {
+    GNUNET_TESTBED_cmd_netjail_start ("netjail-start-1",
+                                      "1",
+                                      "2"),
+    GNUNET_TESTBED_cmd_netjail_start_testbed ("netjail-exec-1",
+                                              binary_argv,
+                                              "1",
+                                              "2",
+                                              &tokenizer_cb,
+                                              &exp_cb),
+    GNUNET_TESTBED_cmd_netjail_stop ("netjail-stop-1",
+                                     "1",
+                                     "2"),
+    GNUNET_TESTING_cmd_end ()
+  };
+
+  GNUNET_TESTING_run (NULL,
+                      commands,
+                      GNUNET_TIME_UNIT_FOREVER_REL);
+}
+
+
+int
+main (int argc,
+      char *const *argv)
+{
+  int rv = 0;
+
+  GNUNET_log_setup ("test-netjail",
+                    "DEBUG",
+                    NULL);
+  GNUNET_SCHEDULER_run (&run,
+                        NULL);
+
+  return rv;
+}
diff --git a/src/testbed/testbed_api_cmd_netjail_start.c 
b/src/testbed/testbed_api_cmd_netjail_start.c
new file mode 100644
index 000000000..320537a61
--- /dev/null
+++ b/src/testbed/testbed_api_cmd_netjail_start.c
@@ -0,0 +1,193 @@
+/*
+      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"
+#include "gnunet_testbed_ng_service.h"
+
+#define NETJAIL_START_SCRIPT "./netjail_start.sh"
+
+struct NetJailState
+{
+  struct GNUNET_ChildWaitHandle *cwh;
+
+  char *local_m;
+
+  char *global_n;
+
+  /**
+   * The process id of the start script.
+   */
+  struct GNUNET_OS_Process *start_proc;
+
+  unsigned int finished;
+};
+
+
+/**
+*
+*
+* @param cls closure
+* @param cmd current CMD being cleaned up.
+*/
+static void
+netjail_start_cleanup (void *cls,
+                       const struct GNUNET_TESTING_Command *cmd)
+{
+  struct NetJailState *ns = cls;
+
+  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;
+  }
+}
+
+
+/**
+*
+*
+* @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 int
+netjail_start_traits (void *cls,
+                      const void **ret,
+                      const char *trait,
+                      unsigned int index)
+{
+  return GNUNET_OK;
+}
+
+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
+  {
+    ns->finished = GNUNET_SYSERR;
+  }
+  GNUNET_OS_process_destroy (ns->start_proc);
+  ns->start_proc = NULL;
+}
+
+
+
+/**
+* Run the "hello world" CMD.
+*
+* @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 *const script_argv[] = {NETJAIL_START_SCRIPT,
+                               ns->local_m,
+                               ns->global_n,
+                               NULL};
+
+  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);
+}
+
+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 binaryname to start.
+ * @return command.
+ */
+struct GNUNET_TESTING_Command
+GNUNET_TESTBED_cmd_netjail_start (const char *label,
+                                  char *local_m,
+                                  char *global_n)
+{
+  struct NetJailState *ns;
+
+  ns = GNUNET_new (struct NetJailState);
+  ns->local_m = local_m;
+  ns->global_n = global_n;
+  ns->finished = GNUNET_NO;
+
+  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/testbed/testbed_api_cmd_netjail_start_testbed.c 
b/src/testbed/testbed_api_cmd_netjail_start_testbed.c
new file mode 100644
index 000000000..da51350a1
--- /dev/null
+++ b/src/testbed/testbed_api_cmd_netjail_start_testbed.c
@@ -0,0 +1,258 @@
+/*
+      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 "gnunet_testbed_ng_service.h"
+#include "testbed_api.h"
+
+#define NETJAIL_EXEC_SCRIPT "./netjail_exec.sh"
+
+struct NetJailState
+{
+
+  /**
+   * The process handle
+   */
+  struct GNUNET_HELPER_Handle *helper;
+
+  GNUNET_MessageTokenizerCallback cb;
+
+  GNUNET_HELPER_ExceptionCallback exp_cb;
+
+  char *binary_name;
+
+  char *local_m;
+
+  char *global_n;
+
+  char **binary_argv;
+
+  /**
+   * The send handle for the helper
+   */
+  struct GNUNET_HELPER_SendHandle *shandle;
+
+  /**
+   * The message corresponding to send handle
+   */
+  struct GNUNET_MessageHeader *msg;
+};
+
+
+/**
+*
+*
+* @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;
+
+  GNUNET_free (ns->binary_name);
+}
+
+
+/**
+*
+*
+* @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 int
+netjail_exec_traits (void *cls,
+                     const void **ret,
+                     const char *trait,
+                     unsigned int index)
+{
+  return GNUNET_OK;
+}
+
+
+// TODO This would be a useful macro.
+/**
+ * Function to join NULL terminated list of arguments
+ *
+ * @param argv1 the NULL terminated list of arguments. Cannot be NULL.
+ * @param argv2 the NULL terminated list of arguments. Cannot be NULL.
+ * @return the joined NULL terminated arguments
+ */
+static char **
+join_argv (const char *const *argv1, const char *const *argv2)
+{
+  char **argvj;
+  char *argv;
+  unsigned int carg = 0;
+  unsigned int cnt;
+
+  carg = 0;
+  argvj = NULL;
+  for (cnt = 0; NULL != argv1[cnt]; cnt++)
+  {
+    argv = GNUNET_strdup (argv1[cnt]);
+    GNUNET_array_append (argvj, carg, argv);
+  }
+  for (cnt = 0; NULL != argv2[cnt]; cnt++)
+  {
+    argv = GNUNET_strdup (argv2[cnt]);
+    GNUNET_array_append (argvj, carg, argv);
+  }
+  GNUNET_array_append (argvj, carg, NULL);
+  return argvj;
+}
+
+
+/**
+ * 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 NetJailState *ns = cls;
+
+  GNUNET_assert (NULL != ns->shandle);
+  ns->shandle = NULL;
+  GNUNET_free (ns->msg);
+  ns->msg = NULL;
+}
+
+
+/**
+* Run the "hello world" CMD.
+*
+* @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;
+  char **helper_argv;
+  struct GNUNET_TESTBED_HelperInit *msg;
+  struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
+  char *const script_argv[] = {NETJAIL_EXEC_SCRIPT,
+                               ns->local_m,
+                               "1",
+                               "1",
+                               NULL};
+  GNUNET_MessageTokenizerCallback cb = ns->cb;
+  GNUNET_HELPER_ExceptionCallback exp_cb = ns->exp_cb;
+
+  if ((GNUNET_YES != GNUNET_DISK_file_test ("test_testbed_api.conf")) ||
+      (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg,
+                                                   "test_testbed_api.conf")))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                _ (
+                  "Unreadable or malformed configuration file `%s', exit 
...\n"),
+                "test_testbed_api.conf");
+  }
+
+  helper_argv = join_argv ((const char **) script_argv,
+                           (const char **) ns->binary_argv);
+
+  ns->helper = GNUNET_HELPER_start (GNUNET_YES,
+                                    NETJAIL_EXEC_SCRIPT,
+                                    helper_argv,
+                                    cb,
+                                    exp_cb,
+                                    ns);
+
+  msg = GNUNET_TESTBED_create_helper_init_msg_ ("127.0.0.1", NULL, cfg);
+  ns->msg = &msg->header;
+  ns->shandle = GNUNET_HELPER_send (ns->helper, &msg->header, GNUNET_NO,
+                                    &clear_msg, ns);
+  if (NULL == ns->shandle)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Send handle is NULL!\n");
+    GNUNET_free (msg);
+  }
+}
+
+
+/**
+ * Create command.
+ *
+ * @param label name for command.
+ * @param binaryname to exec.
+ * @return command.
+ */
+struct GNUNET_TESTING_Command
+GNUNET_TESTBED_cmd_netjail_start_testbed (const char *label,
+                                          char *const binary_argv[],
+                                          char *local_m,
+                                          char *global_n,
+                                          GNUNET_MessageTokenizerCallback cb,
+                                          GNUNET_HELPER_ExceptionCallback 
exp_cb)
+{
+  struct NetJailState *ns;
+  unsigned int append_cnt;
+  char **argvj;
+  char *argv;
+  unsigned int carg = 0;
+
+  ns = GNUNET_new (struct NetJailState);
+  argvj = NULL;
+  for (append_cnt = 0; NULL != binary_argv[append_cnt]; append_cnt++)
+  {
+    argv = GNUNET_strdup (binary_argv[append_cnt]);
+    GNUNET_array_append (argvj,
+                         carg,
+                         argv);
+  }
+  GNUNET_array_append (argvj, carg, NULL);
+
+  ns->binary_argv = argvj;
+
+  ns->local_m = local_m;
+  ns->global_n = global_n;
+  ns->cb = cb;
+  ns->exp_cb = exp_cb;
+
+  struct GNUNET_TESTING_Command cmd = {
+    .cls = ns,
+    .label = label,
+    .run = &netjail_exec_run,
+    .cleanup = &netjail_exec_cleanup,
+    .traits = &netjail_exec_traits
+  };
+
+  return cmd;
+}
diff --git a/src/testbed/testbed_api_cmd_netjail_stop.c 
b/src/testbed/testbed_api_cmd_netjail_stop.c
new file mode 100644
index 000000000..1e6586f94
--- /dev/null
+++ b/src/testbed/testbed_api_cmd_netjail_stop.c
@@ -0,0 +1,197 @@
+/*
+      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"
+#include "gnunet_testbed_ng_service.h"
+
+
+#define NETJAIL_STOP_SCRIPT "./netjail_stop.sh"
+
+struct GNUNET_ChildWaitHandle *cwh;
+
+struct NetJailState
+{
+  char *local_m;
+
+  char *global_n;
+
+  /**
+   * The process id of the start script.
+   */
+  struct GNUNET_OS_Process *stop_proc;
+
+  unsigned int finished;
+};
+
+
+/**
+*
+*
+* @param cls closure
+* @param cmd current CMD being cleaned up.
+*/
+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;
+  }
+}
+
+
+/**
+*
+*
+* @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 int
+netjail_stop_traits (void *cls,
+                     const void **ret,
+                     const char *trait,
+                     unsigned int index)
+{
+  return GNUNET_OK;
+}
+
+
+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;
+}
+
+
+/**
+* Run the "hello world" CMD.
+*
+* @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 *const script_argv[] = {NETJAIL_STOP_SCRIPT,
+                               ns->local_m,
+                               ns->global_n,
+                               NULL};
+
+  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);
+
+}
+
+
+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 binaryname to stop.
+ * @return command.
+ */
+struct GNUNET_TESTING_Command
+GNUNET_TESTBED_cmd_netjail_stop (const char *label,
+                                 char *local_m,
+                                 char *global_n)
+{
+  struct NetJailState *ns;
+
+  ns = GNUNET_new (struct NetJailState);
+  ns->local_m = local_m;
+  ns->global_n = global_n;
+
+  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/testing_api_loop.c b/src/testing/testing_api_loop.c
index 1b50b9ff5..ccee76898 100644
--- a/src/testing/testing_api_loop.c
+++ b/src/testing/testing_api_loop.c
@@ -30,6 +30,9 @@
 #include "gnunet_testing_ng_lib.h"
 #include "testing.h"
 
+#define CHECK_FINISHED_PERIOD \
+  GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
+
 struct GNUNET_TESTING_Interpreter *is;
 
 /**
@@ -188,14 +191,20 @@ run_finish_task_next (void *cls)
   struct FinishTaskClosure *ftc = cls;
   const struct GNUNET_TESTING_Command *cmd = ftc->cmd;
   struct GNUNET_TESTING_Interpreter *is = ftc->is;
+  unsigned int finished = cmd->finish (cmd->cls, &interpreter_next, is);
 
-  if (cmd->finish (cmd->cls, &interpreter_next, is))
+  if (GNUNET_YES == finished)
   {
-    is->finish_task = GNUNET_SCHEDULER_add_now (&run_finish_task_next, ftc);
+    is->finish_task = NULL;
+  }
+  else if (GNUNET_NO == finished)
+  {
+    is->finish_task = GNUNET_SCHEDULER_add_delayed (CHECK_FINISHED_PERIOD,
+                                                    &run_finish_task_next, 
ftc);
   }
   else
   {
-    is->finish_task = NULL;
+    GNUNET_TESTING_interpreter_fail (is);
   }
 
 }
@@ -210,6 +219,7 @@ run_finish_task_sync (void *cls)
   struct FinishTaskClosure *ftc;
   struct SyncState *sync_state = sync_cmd->cls;
   struct GNUNET_SCHEDULER_Task *finish_task = sync_state->finish_task;
+  unsigned int finished = cmd->finish (cmd->cls, &interpreter_next, is);
 
   GNUNET_assert (NULL != finish_task);
   ftc = GNUNET_new (struct FinishTaskClosure);
@@ -222,17 +232,21 @@ run_finish_task_sync (void *cls)
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "The command with label %s did not finish its asynchronous 
task in time.\n",
                 cmd->label);
-    is->result = GNUNET_SYSERR;
-    GNUNET_SCHEDULER_shutdown ();
+    GNUNET_TESTING_interpreter_fail (is);
   }
 
-  if (cmd->finish (cmd->cls, run_finish_task_next, ftc))
+  if (GNUNET_YES == finished)
+  {
+    finish_task = NULL;
+  }
+  else if (GNUNET_NO == finished)
   {
-    finish_task = GNUNET_SCHEDULER_add_now (&run_finish_task_sync, stc);
+    finish_task = GNUNET_SCHEDULER_add_delayed (CHECK_FINISHED_PERIOD,
+                                                &run_finish_task_sync, stc);
   }
   else
   {
-    finish_task = NULL;
+    GNUNET_TESTING_interpreter_fail (is);
   }
 }
 
@@ -252,8 +266,10 @@ start_finish_on_ref (void *cls,
   stc->sync_cmd = cmd;
   stc->is = is;
   sync_state->start_finish_time = GNUNET_TIME_absolute_get ();
-  sync_state->finish_task = GNUNET_SCHEDULER_add_now (&run_finish_task_sync,
-                                                      stc);
+  sync_state->finish_task = GNUNET_SCHEDULER_add_delayed (
+    CHECK_FINISHED_PERIOD,
+    &run_finish_task_sync,
+    stc);
 }
 
 
@@ -281,7 +297,7 @@ GNUNET_TESTING_cmd_finish (const char *finish_label,
 
 
 const struct GNUNET_TESTING_Command
-GNUNET_TESTING_cmd_make_asynchronous (const struct GNUNET_TESTING_Command cmd)
+GNUNET_TESTING_cmd_make_unblocking (const struct GNUNET_TESTING_Command cmd)
 {
 
   GNUNET_assert (NULL != cmd.finish);
@@ -375,10 +391,12 @@ interpreter_run (void *cls)
     GNUNET_SCHEDULER_shutdown ();
     return;
   }
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Running command `%s'\n",
-              cmd->label);
+  else if (NULL != cmd)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Running command `%s'\n",
+                cmd->label);
+  }
   cmd->start_time
     = cmd->last_req_time
       = GNUNET_TIME_absolute_get ();
@@ -388,10 +406,14 @@ interpreter_run (void *cls)
             is);
   if ((NULL != cmd->finish) && (GNUNET_NO == cmd->asynchronous_finish))
   {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Next task will not be called directly!\n");
     ftc = GNUNET_new (struct FinishTaskClosure);
     ftc->cmd = cmd;
     ftc->is = is;
-    cmd->finish_task = GNUNET_SCHEDULER_add_now (run_finish_task_next, ftc);
+    cmd->finish_task = GNUNET_SCHEDULER_add_delayed (CHECK_FINISHED_PERIOD,
+                                                     &run_finish_task_next,
+                                                     ftc);
   }
   else
   {
diff --git a/src/util/child_management.c b/src/util/child_management.c
index 7edc33dc1..7775bfc3d 100644
--- a/src/util/child_management.c
+++ b/src/util/child_management.c
@@ -86,6 +86,10 @@ maint_child_death (void *cls)
 
   (void) cls;
   sig_task = NULL;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Received SIGCHLD.\n");
+
   /* drain pipe */
   pr = GNUNET_DISK_pipe_handle (sigpipe,
                                 GNUNET_DISK_PIPE_END_READ);
@@ -150,17 +154,37 @@ sighandler_child_death (void)
 }
 
 
-void __attribute__ ((constructor))
+// void __attribute__ ((constructor))
+static void
 child_management_start ()
 {
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Trying to start child management.\n");
   if (NULL != sigpipe)
     return; /* already initialized */
   sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE);
   GNUNET_assert (sigpipe != NULL);
   shc_chld =
     GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Child management started.\n");
 }
 
+/**
+ * Clean up.
+ */
+// void __attribute__ ((destructor))
+static void
+child_management_done ()
+{
+  GNUNET_assert (NULL == sig_task);
+  GNUNET_SIGNAL_handler_uninstall (shc_chld);
+  shc_chld = NULL;
+  GNUNET_DISK_pipe_close (sigpipe);
+  sigpipe = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Child management stopped.\n");
+}
 
 struct GNUNET_ChildWaitHandle *
 GNUNET_wait_child (struct GNUNET_OS_Process *proc,
@@ -189,7 +213,6 @@ GNUNET_wait_child (struct GNUNET_OS_Process *proc,
   return cwh;
 }
 
-
 void
 GNUNET_wait_child_cancel (struct GNUNET_ChildWaitHandle *cwh)
 {
@@ -198,22 +221,9 @@ GNUNET_wait_child_cancel (struct GNUNET_ChildWaitHandle 
*cwh)
                                cwh);
   if (NULL == cwh_head)
   {
+    child_management_done ();
     GNUNET_SCHEDULER_cancel (sig_task);
     sig_task = NULL;
   }
   GNUNET_free (cwh);
 }
-
-
-/**
- * Clean up.
- */
-void __attribute__ ((destructor))
-GNUNET_CM_done ()
-{
-  GNUNET_assert (NULL == sig_task);
-  GNUNET_SIGNAL_handler_uninstall (shc_chld);
-  shc_chld = NULL;
-  GNUNET_DISK_pipe_close (sigpipe);
-  sigpipe = NULL;
-}

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]