aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authort3sserakt <t3ss@posteo.de>2021-06-30 13:04:40 +0200
committert3sserakt <t3ss@posteo.de>2021-06-30 13:04:40 +0200
commit13dbe5418c1e61bb3c433efa7c2dc412e08b356d (patch)
treeba53f0f1bb3f365a41c079aa3190fb98caf9d1b6 /src
parent3ae831780b5681764a7d0505fa94f3fdaa43e1d8 (diff)
downloadgnunet-13dbe5418c1e61bb3c433efa7c2dc412e08b356d.tar.gz
gnunet-13dbe5418c1e61bb3c433efa7c2dc412e08b356d.zip
- starting testbed with netjail
Diffstat (limited to 'src')
-rw-r--r--src/include/gnunet_testbed_ng_service.h39
-rw-r--r--src/include/gnunet_testing_ng_lib.h2
-rw-r--r--src/testbed/Makefile.am12
-rwxr-xr-xsrc/testbed/netjail_core.sh107
-rwxr-xr-xsrc/testbed/netjail_exec.sh19
-rwxr-xr-xsrc/testbed/netjail_start.sh52
-rwxr-xr-xsrc/testbed/netjail_stop.sh26
-rw-r--r--src/testbed/test_testbed_api_cmd_netjail.c94
-rw-r--r--src/testbed/testbed_api_cmd_netjail_start.c193
-rw-r--r--src/testbed/testbed_api_cmd_netjail_start_testbed.c258
-rw-r--r--src/testbed/testbed_api_cmd_netjail_stop.c197
-rw-r--r--src/testing/testing_api_loop.c54
-rw-r--r--src/util/child_management.c42
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);
213void 213void
214GNUNET_TESTBED_shutdown_service (struct TngState *ss); 214GNUNET_TESTBED_shutdown_service (struct TngState *ss);
215 215
216/**
217 * Create command.
218 *
219 * @param label name for command.
220 * @param binaryname to start.
221 * @return command.
222 */
223struct GNUNET_TESTING_Command
224GNUNET_TESTBED_cmd_netjail_start (const char *label,
225 char *local_m,
226 char *global_n);
227
228/**
229 * Create command.
230 *
231 * @param label name for command.
232 * @param binaryname to exec.
233 * @return command.
234 */
235struct GNUNET_TESTING_Command
236GNUNET_TESTBED_cmd_netjail_start_testbed (const char *label,
237 char *const binary_argv[],
238 char *local_m,
239 char *global_n,
240 GNUNET_MessageTokenizerCallback cb,
241 GNUNET_HELPER_ExceptionCallback exp_cb);
242
243/**
244 * Create command.
245 *
246 * @param label name for command.
247 * @param binaryname to stop.
248 * @return command.
249 */
250struct GNUNET_TESTING_Command
251GNUNET_TESTBED_cmd_netjail_stop (const char *label,
252 char *local_m,
253 char *global_n);
254
216#endif 255#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
101 * @param cont function to call upon completion, can be NULL 101 * @param cont function to call upon completion, can be NULL
102 * @param cont_cls closure for @a cont 102 * @param cont_cls closure for @a cont
103 */ 103 */
104 bool 104 int
105 (*finish)(void *cls, 105 (*finish)(void *cls,
106 GNUNET_SCHEDULER_TaskCallback cont, 106 GNUNET_SCHEDULER_TaskCallback cont,
107 void *cont_cls); 107 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 = \
92 libgnunettestbed.la 92 libgnunettestbed.la
93 93
94libgnunettestbed_la_SOURCES = \ 94libgnunettestbed_la_SOURCES = \
95 testbed_api_cmd_netjail_start.c \
96 testbed_api_cmd_netjail_start_testbed.c \
97 testbed_api_cmd_netjail_stop.c \
95 testbed_api.c testbed_api.h testbed.h \ 98 testbed_api.c testbed_api.h testbed.h \
96 testbed_api_hosts.c testbed_api_hosts.h testbed_helper.h \ 99 testbed_api_hosts.c testbed_api_hosts.h testbed_helper.h \
97 testbed_api_cmd_controller.c \ 100 testbed_api_cmd_controller.c \
@@ -131,6 +134,7 @@ generate_underlay_topology_LDADD = $(XLIB) \
131 $(LTLIBINTL) -lsqlite3 134 $(LTLIBINTL) -lsqlite3
132 135
133check_PROGRAMS = \ 136check_PROGRAMS = \
137 test_testbed_api_cmd_netjail \
134 test_testbed_api_hosts \ 138 test_testbed_api_hosts \
135 test_gnunet_helper_testbed \ 139 test_gnunet_helper_testbed \
136 test_testbed_api_controllerlink \ 140 test_testbed_api_controllerlink \
@@ -165,6 +169,7 @@ check_PROGRAMS = \
165if ENABLE_TEST_RUN 169if ENABLE_TEST_RUN
166 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; 170 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
167 TESTS = \ 171 TESTS = \
172 test_testbed_api_cmd_netjail \
168 test_testbed_api \ 173 test_testbed_api \
169 test_testbed_api_sd \ 174 test_testbed_api_sd \
170 test_testbed_api_operations \ 175 test_testbed_api_operations \
@@ -195,6 +200,13 @@ if ENABLE_TEST_RUN
195 $(underlay_testcases) 200 $(underlay_testcases)
196endif 201endif
197 202
203test_testbed_api_cmd_netjail_SOURCES = \
204 test_testbed_api_cmd_netjail.c
205test_testbed_api_cmd_netjail_LDADD = \
206 $(top_builddir)/src/testing/libgnunettesting.la \
207 $(top_builddir)/src/util/libgnunetutil.la \
208 libgnunettestbed.la
209
198test_testbed_api_SOURCES = \ 210test_testbed_api_SOURCES = \
199 test_testbed_api.c 211 test_testbed_api.c
200test_testbed_api_LDADD = \ 212test_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 @@
1#!/bin/sh
2#
3
4JAILOR=${SUDO_USER:?must run in sudo}
5
6# running with `sudo` is required to be
7# able running the actual commands as the
8# original user.
9
10export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
11
12netjail_check() {
13 NODE_COUNT=$1
14
15 FD_COUNT=$(($(ls /proc/self/fd | wc -w) - 4))
16
17 # quit if `$FD_COUNT < ($LOCAL_M * $GLOBAL_N * 2)`:
18 # the script also requires `sudo -C ($FD_COUNT + 4)`
19 # so you need 'Defaults closefrom_override' in the
20 # sudoers file.
21
22 if [ $FD_COUNT -lt $(($NODE_COUNT * 2)) ]; then
23 echo "File descriptors do not match requirements!" >&2
24 exit 1
25 fi
26}
27
28netjail_print_name() {
29 printf "%s%02x%02x" $1 $2 ${3:-0}
30}
31
32netjail_bridge() {
33 BRIDGE=$1
34
35 ip link add $BRIDGE type bridge
36 ip link set dev $BRIDGE up
37}
38
39netjail_bridge_clear() {
40 BRIDGE=$1
41
42 ip link delete $BRIDGE
43}
44
45netjail_node() {
46 NODE=$1
47
48 ip netns add $NODE
49}
50
51netjail_node_clear() {
52 NODE=$1
53
54 ip netns delete $NODE
55}
56
57netjail_node_link_bridge() {
58 NODE=$1
59 BRIDGE=$2
60 ADDRESS=$3
61 MASK=$4
62
63 LINK_IF="$NODE-$BRIDGE-0"
64 LINK_BR="$NODE-$BRIDGE-1"
65
66 ip link add $LINK_IF type veth peer name $LINK_BR
67 ip link set $LINK_IF netns $NODE
68 ip link set $LINK_BR master $BRIDGE
69
70 ip -n $NODE addr add "$ADDRESS/$MASK" dev $LINK_IF
71 ip -n $NODE link set $LINK_IF up
72 ip -n $NODE link set up dev lo
73
74 ip link set $LINK_BR up
75}
76
77netjail_node_add_nat() {
78 NODE=$1
79 ADDRESS=$2
80 MASK=$3
81
82 ip netns exec $NODE iptables -t nat -A POSTROUTING -s "$ADDRESS/$MASK" -j MASQUERADE
83}
84
85netjail_node_add_default() {
86 NODE=$1
87 ADDRESS=$2
88
89 ip -n $NODE route add default via $ADDRESS
90}
91
92netjail_node_exec() {
93 NODE=$1
94 FD_IN=$2
95 FD_OUT=$3
96 shift 3
97
98 unshare -fp --kill-child -- ip netns exec $NODE sudo -u $JAILOR -- $@ 1>& $FD_OUT 0<& $FD_IN
99}
100
101netjail_node_exec_without_fds() {
102 local NODE=$1
103 shift 3
104
105 unshare -fp --kill-child -- ip netns exec $NODE sudo -u $JAILOR -- $@
106}
107
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 @@
1#!/bin/sh
2. "./netjail_core.sh"
3
4set -eu
5set -x
6
7export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
8
9LOCAL_M=$1
10M=$2
11N=$3
12
13NODE=$(netjail_print_name "N" $N $M)
14INDEX=$(($LOCAL_M * ($N - 1) + $M - 1))
15
16FD_X=$(($INDEX * 2 + 3 + 0))
17FD_Y=$(($INDEX * 2 + 3 + 1))
18
19netjail_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 @@
1#!/bin/sh
2. "./netjail_core.sh"
3
4set -eu
5set -x
6
7export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
8
9LOCAL_M=$1
10GLOBAL_N=$2
11
12# TODO: stunserver? ..and globally known peer?
13
14shift 2
15
16LOCAL_GROUP="192.168.15"
17GLOBAL_GROUP="92.68.150"
18
19NETWORK_NET=$(netjail_print_name "n" $GLOBAL_N $LOCAL_M)
20
21netjail_bridge $NETWORK_NET
22
23for N in $(seq $GLOBAL_N); do
24 ROUTER=$(netjail_print_name "R" $N)
25
26 netjail_node $ROUTER
27 netjail_node_link_bridge $ROUTER $NETWORK_NET "$GLOBAL_GROUP.$N" 24
28
29 ROUTER_NET=$(netjail_print_name "r" $N)
30
31 netjail_bridge $ROUTER_NET
32
33 for M in $(seq $LOCAL_M); do
34 NODE=$(netjail_print_name "N" $N $M)
35
36 netjail_node $NODE
37 netjail_node_link_bridge $NODE $ROUTER_NET "$LOCAL_GROUP.$M" 24
38 done
39
40 ROUTER_ADDR="$LOCAL_GROUP.$(($LOCAL_M+1))"
41
42 netjail_node_link_bridge $ROUTER $ROUTER_NET $ROUTER_ADDR 24
43 netjail_node_add_nat $ROUTER $ROUTER_ADDR 24
44
45 for M in $(seq $LOCAL_M); do
46 NODE=$(netjail_print_name "N" $N $M)
47
48 netjail_node_add_default $NODE $ROUTER_ADDR
49 done
50done
51
52
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 @@
1#!/bin/sh
2. "./netjail_core.sh"
3
4set -eu
5set -x
6
7export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
8
9LOCAL_M=$1
10GLOBAL_N=$2
11NETWORK_NET=$(netjail_print_name "n" $GLOBAL_N $LOCAL_M)
12
13shift 2
14
15for N in $(seq $GLOBAL_N); do
16 for M in $(seq $LOCAL_M); do
17 netjail_node_clear $(netjail_print_name "N" $N $M)
18 done
19
20 netjail_bridge_clear $(netjail_print_name "r" $N)
21 netjail_node_clear $(netjail_print_name "R" $N)
22done
23
24netjail_bridge_clear $NETWORK_NET
25
26echo "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 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testing/test_testing_api_cmd_netjail.c
23 * @brief Test case executing a script in a network name space.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_testing_ng_lib.h"
28#include "gnunet_testbed_ng_service.h"
29#include "gnunet_util_lib.h"
30
31#define HELPER_TESTBED_BINARY "../testbed/gnunet-helper-testbed"
32
33static int
34tokenizer_cb (void *cls, const struct GNUNET_MessageHeader *message)
35{
36 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called tokenizer.\n");
37 return GNUNET_OK;
38}
39
40
41static void
42exp_cb (void *cls)
43{
44 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called exp_cb.\n");
45}
46
47
48/**
49 * Main function to run the test cases.
50 *
51 * @param cls not used.
52 *
53 */
54static void
55run (void *cls)
56{
57 char *const binary_argv[3] = {HELPER_TESTBED_BINARY, NULL};
58
59 struct GNUNET_TESTING_Command commands[] = {
60 GNUNET_TESTBED_cmd_netjail_start ("netjail-start-1",
61 "1",
62 "2"),
63 GNUNET_TESTBED_cmd_netjail_start_testbed ("netjail-exec-1",
64 binary_argv,
65 "1",
66 "2",
67 &tokenizer_cb,
68 &exp_cb),
69 GNUNET_TESTBED_cmd_netjail_stop ("netjail-stop-1",
70 "1",
71 "2"),
72 GNUNET_TESTING_cmd_end ()
73 };
74
75 GNUNET_TESTING_run (NULL,
76 commands,
77 GNUNET_TIME_UNIT_FOREVER_REL);
78}
79
80
81int
82main (int argc,
83 char *const *argv)
84{
85 int rv = 0;
86
87 GNUNET_log_setup ("test-netjail",
88 "DEBUG",
89 NULL);
90 GNUNET_SCHEDULER_run (&run,
91 NULL);
92
93 return rv;
94}
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 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testing/testing_api_cmd_hello_world.c
23 * @brief Command to start the netjail script.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_testing_ng_lib.h"
29#include "gnunet_testbed_ng_service.h"
30
31#define NETJAIL_START_SCRIPT "./netjail_start.sh"
32
33struct NetJailState
34{
35 struct GNUNET_ChildWaitHandle *cwh;
36
37 char *local_m;
38
39 char *global_n;
40
41 /**
42 * The process id of the start script.
43 */
44 struct GNUNET_OS_Process *start_proc;
45
46 unsigned int finished;
47};
48
49
50/**
51*
52*
53* @param cls closure
54* @param cmd current CMD being cleaned up.
55*/
56static void
57netjail_start_cleanup (void *cls,
58 const struct GNUNET_TESTING_Command *cmd)
59{
60 struct NetJailState *ns = cls;
61
62 if (NULL != ns->cwh)
63 {
64 GNUNET_wait_child_cancel (ns->cwh);
65 ns->cwh = NULL;
66 }
67 if (NULL != ns->start_proc)
68 {
69 GNUNET_assert (0 ==
70 GNUNET_OS_process_kill (ns->start_proc,
71 SIGKILL));
72 GNUNET_assert (GNUNET_OK ==
73 GNUNET_OS_process_wait (ns->start_proc));
74 GNUNET_OS_process_destroy (ns->start_proc);
75 ns->start_proc = NULL;
76 }
77}
78
79
80/**
81*
82*
83* @param cls closure.
84* @param[out] ret result
85* @param trait name of the trait.
86* @param index index number of the object to offer.
87* @return #GNUNET_OK on success.
88*/
89static int
90netjail_start_traits (void *cls,
91 const void **ret,
92 const char *trait,
93 unsigned int index)
94{
95 return GNUNET_OK;
96}
97
98static void
99child_completed_callback (void *cls,
100 enum GNUNET_OS_ProcessStatusType type,
101 long unsigned int exit_code)
102{
103 struct NetJailState *ns = cls;
104
105 if (0 == exit_code)
106 {
107 ns->finished = GNUNET_YES;
108 }
109 else
110 {
111 ns->finished = GNUNET_SYSERR;
112 }
113 GNUNET_OS_process_destroy (ns->start_proc);
114 ns->start_proc = NULL;
115}
116
117
118
119/**
120* Run the "hello world" CMD.
121*
122* @param cls closure.
123* @param cmd CMD being run.
124* @param is interpreter state.
125*/
126static void
127netjail_start_run (void *cls,
128 const struct GNUNET_TESTING_Command *cmd,
129 struct GNUNET_TESTING_Interpreter *is)
130{
131 struct NetJailState *ns = cls;
132 char *const script_argv[] = {NETJAIL_START_SCRIPT,
133 ns->local_m,
134 ns->global_n,
135 NULL};
136
137 ns->start_proc = GNUNET_OS_start_process_vap (GNUNET_OS_INHERIT_STD_ERR,
138 NULL,
139 NULL,
140 NULL,
141 NETJAIL_START_SCRIPT,
142 script_argv);
143
144 ns->cwh = GNUNET_wait_child (ns->start_proc,
145 &child_completed_callback,
146 ns);
147 GNUNET_break (NULL != ns->cwh);
148}
149
150static int
151netjail_start_finish (void *cls,
152 GNUNET_SCHEDULER_TaskCallback cont,
153 void *cont_cls)
154{
155 struct NetJailState *ns = cls;
156
157 if (ns->finished)
158 {
159 cont (cont_cls);
160 }
161 return ns->finished;
162}
163
164/**
165 * Create command.
166 *
167 * @param label name for command.
168 * @param binaryname to start.
169 * @return command.
170 */
171struct GNUNET_TESTING_Command
172GNUNET_TESTBED_cmd_netjail_start (const char *label,
173 char *local_m,
174 char *global_n)
175{
176 struct NetJailState *ns;
177
178 ns = GNUNET_new (struct NetJailState);
179 ns->local_m = local_m;
180 ns->global_n = global_n;
181 ns->finished = GNUNET_NO;
182
183 struct GNUNET_TESTING_Command cmd = {
184 .cls = ns,
185 .label = label,
186 .run = &netjail_start_run,
187 .finish = &netjail_start_finish,
188 .cleanup = &netjail_start_cleanup,
189 .traits = &netjail_start_traits
190 };
191
192 return cmd;
193}
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 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testing/testing_api_cmd_hello_world.c
23 * @brief Command to start the netjail peers.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_testing_ng_lib.h"
28#include "gnunet_testbed_ng_service.h"
29#include "testbed_api.h"
30
31#define NETJAIL_EXEC_SCRIPT "./netjail_exec.sh"
32
33struct NetJailState
34{
35
36 /**
37 * The process handle
38 */
39 struct GNUNET_HELPER_Handle *helper;
40
41 GNUNET_MessageTokenizerCallback cb;
42
43 GNUNET_HELPER_ExceptionCallback exp_cb;
44
45 char *binary_name;
46
47 char *local_m;
48
49 char *global_n;
50
51 char **binary_argv;
52
53 /**
54 * The send handle for the helper
55 */
56 struct GNUNET_HELPER_SendHandle *shandle;
57
58 /**
59 * The message corresponding to send handle
60 */
61 struct GNUNET_MessageHeader *msg;
62};
63
64
65/**
66*
67*
68* @param cls closure
69* @param cmd current CMD being cleaned up.
70*/
71static void
72netjail_exec_cleanup (void *cls,
73 const struct GNUNET_TESTING_Command *cmd)
74{
75 struct NetJailState *ns = cls;
76
77 GNUNET_free (ns->binary_name);
78}
79
80
81/**
82*
83*
84* @param cls closure.
85* @param[out] ret result
86* @param trait name of the trait.
87* @param index index number of the object to offer.
88* @return #GNUNET_OK on success.
89*/
90static int
91netjail_exec_traits (void *cls,
92 const void **ret,
93 const char *trait,
94 unsigned int index)
95{
96 return GNUNET_OK;
97}
98
99
100// TODO This would be a useful macro.
101/**
102 * Function to join NULL terminated list of arguments
103 *
104 * @param argv1 the NULL terminated list of arguments. Cannot be NULL.
105 * @param argv2 the NULL terminated list of arguments. Cannot be NULL.
106 * @return the joined NULL terminated arguments
107 */
108static char **
109join_argv (const char *const *argv1, const char *const *argv2)
110{
111 char **argvj;
112 char *argv;
113 unsigned int carg = 0;
114 unsigned int cnt;
115
116 carg = 0;
117 argvj = NULL;
118 for (cnt = 0; NULL != argv1[cnt]; cnt++)
119 {
120 argv = GNUNET_strdup (argv1[cnt]);
121 GNUNET_array_append (argvj, carg, argv);
122 }
123 for (cnt = 0; NULL != argv2[cnt]; cnt++)
124 {
125 argv = GNUNET_strdup (argv2[cnt]);
126 GNUNET_array_append (argvj, carg, argv);
127 }
128 GNUNET_array_append (argvj, carg, NULL);
129 return argvj;
130}
131
132
133/**
134 * Continuation function from GNUNET_HELPER_send()
135 *
136 * @param cls closure
137 * @param result GNUNET_OK on success,
138 * GNUNET_NO if helper process died
139 * GNUNET_SYSERR during GNUNET_HELPER_stop
140 */
141static void
142clear_msg (void *cls, int result)
143{
144 struct NetJailState *ns = cls;
145
146 GNUNET_assert (NULL != ns->shandle);
147 ns->shandle = NULL;
148 GNUNET_free (ns->msg);
149 ns->msg = NULL;
150}
151
152
153/**
154* Run the "hello world" CMD.
155*
156* @param cls closure.
157* @param cmd CMD being run.
158* @param is interpreter state.
159*/
160static void
161netjail_exec_run (void *cls,
162 const struct GNUNET_TESTING_Command *cmd,
163 struct GNUNET_TESTING_Interpreter *is)
164{
165 struct NetJailState *ns = cls;
166 char **helper_argv;
167 struct GNUNET_TESTBED_HelperInit *msg;
168 struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
169 char *const script_argv[] = {NETJAIL_EXEC_SCRIPT,
170 ns->local_m,
171 "1",
172 "1",
173 NULL};
174 GNUNET_MessageTokenizerCallback cb = ns->cb;
175 GNUNET_HELPER_ExceptionCallback exp_cb = ns->exp_cb;
176
177 if ((GNUNET_YES != GNUNET_DISK_file_test ("test_testbed_api.conf")) ||
178 (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg,
179 "test_testbed_api.conf")))
180 {
181 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
182 _ (
183 "Unreadable or malformed configuration file `%s', exit ...\n"),
184 "test_testbed_api.conf");
185 }
186
187 helper_argv = join_argv ((const char **) script_argv,
188 (const char **) ns->binary_argv);
189
190 ns->helper = GNUNET_HELPER_start (GNUNET_YES,
191 NETJAIL_EXEC_SCRIPT,
192 helper_argv,
193 cb,
194 exp_cb,
195 ns);
196
197 msg = GNUNET_TESTBED_create_helper_init_msg_ ("127.0.0.1", NULL, cfg);
198 ns->msg = &msg->header;
199 ns->shandle = GNUNET_HELPER_send (ns->helper, &msg->header, GNUNET_NO,
200 &clear_msg, ns);
201 if (NULL == ns->shandle)
202 {
203 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
204 "Send handle is NULL!\n");
205 GNUNET_free (msg);
206 }
207}
208
209
210/**
211 * Create command.
212 *
213 * @param label name for command.
214 * @param binaryname to exec.
215 * @return command.
216 */
217struct GNUNET_TESTING_Command
218GNUNET_TESTBED_cmd_netjail_start_testbed (const char *label,
219 char *const binary_argv[],
220 char *local_m,
221 char *global_n,
222 GNUNET_MessageTokenizerCallback cb,
223 GNUNET_HELPER_ExceptionCallback exp_cb)
224{
225 struct NetJailState *ns;
226 unsigned int append_cnt;
227 char **argvj;
228 char *argv;
229 unsigned int carg = 0;
230
231 ns = GNUNET_new (struct NetJailState);
232 argvj = NULL;
233 for (append_cnt = 0; NULL != binary_argv[append_cnt]; append_cnt++)
234 {
235 argv = GNUNET_strdup (binary_argv[append_cnt]);
236 GNUNET_array_append (argvj,
237 carg,
238 argv);
239 }
240 GNUNET_array_append (argvj, carg, NULL);
241
242 ns->binary_argv = argvj;
243
244 ns->local_m = local_m;
245 ns->global_n = global_n;
246 ns->cb = cb;
247 ns->exp_cb = exp_cb;
248
249 struct GNUNET_TESTING_Command cmd = {
250 .cls = ns,
251 .label = label,
252 .run = &netjail_exec_run,
253 .cleanup = &netjail_exec_cleanup,
254 .traits = &netjail_exec_traits
255 };
256
257 return cmd;
258}
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 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testing/testing_api_cmd_hello_world.c
23 * @brief Command to stop the netjail script.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_testing_ng_lib.h"
29#include "gnunet_testbed_ng_service.h"
30
31
32#define NETJAIL_STOP_SCRIPT "./netjail_stop.sh"
33
34struct GNUNET_ChildWaitHandle *cwh;
35
36struct NetJailState
37{
38 char *local_m;
39
40 char *global_n;
41
42 /**
43 * The process id of the start script.
44 */
45 struct GNUNET_OS_Process *stop_proc;
46
47 unsigned int finished;
48};
49
50
51/**
52*
53*
54* @param cls closure
55* @param cmd current CMD being cleaned up.
56*/
57static void
58netjail_stop_cleanup (void *cls,
59 const struct GNUNET_TESTING_Command *cmd)
60{
61 struct NetJailState *ns = cls;
62
63 if (NULL != cwh)
64 {
65 GNUNET_wait_child_cancel (cwh);
66 cwh = NULL;
67 }
68 if (NULL != ns->stop_proc)
69 {
70 GNUNET_assert (0 ==
71 GNUNET_OS_process_kill (ns->stop_proc,
72 SIGKILL));
73 GNUNET_assert (GNUNET_OK ==
74 GNUNET_OS_process_wait (ns->stop_proc));
75 GNUNET_OS_process_destroy (ns->stop_proc);
76 ns->stop_proc = NULL;
77 }
78}
79
80
81/**
82*
83*
84* @param cls closure.
85* @param[out] ret result
86* @param trait name of the trait.
87* @param index index number of the object to offer.
88* @return #GNUNET_OK on success.
89*/
90static int
91netjail_stop_traits (void *cls,
92 const void **ret,
93 const char *trait,
94 unsigned int index)
95{
96 return GNUNET_OK;
97}
98
99
100static void
101child_completed_callback (void *cls,
102 enum GNUNET_OS_ProcessStatusType type,
103 long unsigned int exit_code)
104{
105 struct NetJailState *ns = cls;
106
107 cwh = NULL;
108 if (0 == exit_code)
109 {
110 ns->finished = GNUNET_YES;
111 }
112 else
113 {
114 ns->finished = GNUNET_SYSERR;
115 }
116 GNUNET_OS_process_destroy (ns->stop_proc);
117 ns->stop_proc = NULL;
118}
119
120
121/**
122* Run the "hello world" CMD.
123*
124* @param cls closure.
125* @param cmd CMD being run.
126* @param is interpreter state.
127*/
128static void
129netjail_stop_run (void *cls,
130 const struct GNUNET_TESTING_Command *cmd,
131 struct GNUNET_TESTING_Interpreter *is)
132{
133 struct NetJailState *ns = cls;
134 char *const script_argv[] = {NETJAIL_STOP_SCRIPT,
135 ns->local_m,
136 ns->global_n,
137 NULL};
138
139 ns->stop_proc = GNUNET_OS_start_process_vap (GNUNET_OS_INHERIT_STD_ERR,
140 NULL,
141 NULL,
142 NULL,
143 NETJAIL_STOP_SCRIPT,
144 script_argv);
145
146 cwh = GNUNET_wait_child (ns->stop_proc,
147 &child_completed_callback,
148 ns);
149 GNUNET_break (NULL != cwh);
150
151}
152
153
154static int
155netjail_stop_finish (void *cls,
156 GNUNET_SCHEDULER_TaskCallback cont,
157 void *cont_cls)
158{
159 struct NetJailState *ns = cls;
160
161 if (ns->finished)
162 {
163 cont (cont_cls);
164 }
165 return ns->finished;
166}
167
168
169/**
170 * Create command.
171 *
172 * @param label name for command.
173 * @param binaryname to stop.
174 * @return command.
175 */
176struct GNUNET_TESTING_Command
177GNUNET_TESTBED_cmd_netjail_stop (const char *label,
178 char *local_m,
179 char *global_n)
180{
181 struct NetJailState *ns;
182
183 ns = GNUNET_new (struct NetJailState);
184 ns->local_m = local_m;
185 ns->global_n = global_n;
186
187 struct GNUNET_TESTING_Command cmd = {
188 .cls = ns,
189 .label = label,
190 .run = &netjail_stop_run,
191 .finish = &netjail_stop_finish,
192 .cleanup = &netjail_stop_cleanup,
193 .traits = &netjail_stop_traits
194 };
195
196 return cmd;
197}
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 @@
30#include "gnunet_testing_ng_lib.h" 30#include "gnunet_testing_ng_lib.h"
31#include "testing.h" 31#include "testing.h"
32 32
33#define CHECK_FINISHED_PERIOD \
34 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
35
33struct GNUNET_TESTING_Interpreter *is; 36struct GNUNET_TESTING_Interpreter *is;
34 37
35/** 38/**
@@ -188,14 +191,20 @@ run_finish_task_next (void *cls)
188 struct FinishTaskClosure *ftc = cls; 191 struct FinishTaskClosure *ftc = cls;
189 const struct GNUNET_TESTING_Command *cmd = ftc->cmd; 192 const struct GNUNET_TESTING_Command *cmd = ftc->cmd;
190 struct GNUNET_TESTING_Interpreter *is = ftc->is; 193 struct GNUNET_TESTING_Interpreter *is = ftc->is;
194 unsigned int finished = cmd->finish (cmd->cls, &interpreter_next, is);
191 195
192 if (cmd->finish (cmd->cls, &interpreter_next, is)) 196 if (GNUNET_YES == finished)
193 { 197 {
194 is->finish_task = GNUNET_SCHEDULER_add_now (&run_finish_task_next, ftc); 198 is->finish_task = NULL;
199 }
200 else if (GNUNET_NO == finished)
201 {
202 is->finish_task = GNUNET_SCHEDULER_add_delayed (CHECK_FINISHED_PERIOD,
203 &run_finish_task_next, ftc);
195 } 204 }
196 else 205 else
197 { 206 {
198 is->finish_task = NULL; 207 GNUNET_TESTING_interpreter_fail (is);
199 } 208 }
200 209
201} 210}
@@ -210,6 +219,7 @@ run_finish_task_sync (void *cls)
210 struct FinishTaskClosure *ftc; 219 struct FinishTaskClosure *ftc;
211 struct SyncState *sync_state = sync_cmd->cls; 220 struct SyncState *sync_state = sync_cmd->cls;
212 struct GNUNET_SCHEDULER_Task *finish_task = sync_state->finish_task; 221 struct GNUNET_SCHEDULER_Task *finish_task = sync_state->finish_task;
222 unsigned int finished = cmd->finish (cmd->cls, &interpreter_next, is);
213 223
214 GNUNET_assert (NULL != finish_task); 224 GNUNET_assert (NULL != finish_task);
215 ftc = GNUNET_new (struct FinishTaskClosure); 225 ftc = GNUNET_new (struct FinishTaskClosure);
@@ -222,17 +232,21 @@ run_finish_task_sync (void *cls)
222 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 232 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
223 "The command with label %s did not finish its asynchronous task in time.\n", 233 "The command with label %s did not finish its asynchronous task in time.\n",
224 cmd->label); 234 cmd->label);
225 is->result = GNUNET_SYSERR; 235 GNUNET_TESTING_interpreter_fail (is);
226 GNUNET_SCHEDULER_shutdown ();
227 } 236 }
228 237
229 if (cmd->finish (cmd->cls, run_finish_task_next, ftc)) 238 if (GNUNET_YES == finished)
239 {
240 finish_task = NULL;
241 }
242 else if (GNUNET_NO == finished)
230 { 243 {
231 finish_task = GNUNET_SCHEDULER_add_now (&run_finish_task_sync, stc); 244 finish_task = GNUNET_SCHEDULER_add_delayed (CHECK_FINISHED_PERIOD,
245 &run_finish_task_sync, stc);
232 } 246 }
233 else 247 else
234 { 248 {
235 finish_task = NULL; 249 GNUNET_TESTING_interpreter_fail (is);
236 } 250 }
237} 251}
238 252
@@ -252,8 +266,10 @@ start_finish_on_ref (void *cls,
252 stc->sync_cmd = cmd; 266 stc->sync_cmd = cmd;
253 stc->is = is; 267 stc->is = is;
254 sync_state->start_finish_time = GNUNET_TIME_absolute_get (); 268 sync_state->start_finish_time = GNUNET_TIME_absolute_get ();
255 sync_state->finish_task = GNUNET_SCHEDULER_add_now (&run_finish_task_sync, 269 sync_state->finish_task = GNUNET_SCHEDULER_add_delayed (
256 stc); 270 CHECK_FINISHED_PERIOD,
271 &run_finish_task_sync,
272 stc);
257} 273}
258 274
259 275
@@ -281,7 +297,7 @@ GNUNET_TESTING_cmd_finish (const char *finish_label,
281 297
282 298
283const struct GNUNET_TESTING_Command 299const struct GNUNET_TESTING_Command
284GNUNET_TESTING_cmd_make_asynchronous (const struct GNUNET_TESTING_Command cmd) 300GNUNET_TESTING_cmd_make_unblocking (const struct GNUNET_TESTING_Command cmd)
285{ 301{
286 302
287 GNUNET_assert (NULL != cmd.finish); 303 GNUNET_assert (NULL != cmd.finish);
@@ -375,10 +391,12 @@ interpreter_run (void *cls)
375 GNUNET_SCHEDULER_shutdown (); 391 GNUNET_SCHEDULER_shutdown ();
376 return; 392 return;
377 } 393 }
378 394 else if (NULL != cmd)
379 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 395 {
380 "Running command `%s'\n", 396 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
381 cmd->label); 397 "Running command `%s'\n",
398 cmd->label);
399 }
382 cmd->start_time 400 cmd->start_time
383 = cmd->last_req_time 401 = cmd->last_req_time
384 = GNUNET_TIME_absolute_get (); 402 = GNUNET_TIME_absolute_get ();
@@ -388,10 +406,14 @@ interpreter_run (void *cls)
388 is); 406 is);
389 if ((NULL != cmd->finish) && (GNUNET_NO == cmd->asynchronous_finish)) 407 if ((NULL != cmd->finish) && (GNUNET_NO == cmd->asynchronous_finish))
390 { 408 {
409 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
410 "Next task will not be called directly!\n");
391 ftc = GNUNET_new (struct FinishTaskClosure); 411 ftc = GNUNET_new (struct FinishTaskClosure);
392 ftc->cmd = cmd; 412 ftc->cmd = cmd;
393 ftc->is = is; 413 ftc->is = is;
394 cmd->finish_task = GNUNET_SCHEDULER_add_now (run_finish_task_next, ftc); 414 cmd->finish_task = GNUNET_SCHEDULER_add_delayed (CHECK_FINISHED_PERIOD,
415 &run_finish_task_next,
416 ftc);
395 } 417 }
396 else 418 else
397 { 419 {
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)
86 86
87 (void) cls; 87 (void) cls;
88 sig_task = NULL; 88 sig_task = NULL;
89
90 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
91 "Received SIGCHLD.\n");
92
89 /* drain pipe */ 93 /* drain pipe */
90 pr = GNUNET_DISK_pipe_handle (sigpipe, 94 pr = GNUNET_DISK_pipe_handle (sigpipe,
91 GNUNET_DISK_PIPE_END_READ); 95 GNUNET_DISK_PIPE_END_READ);
@@ -150,17 +154,37 @@ sighandler_child_death (void)
150} 154}
151 155
152 156
153void __attribute__ ((constructor)) 157// void __attribute__ ((constructor))
158static void
154child_management_start () 159child_management_start ()
155{ 160{
161 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
162 "Trying to start child management.\n");
156 if (NULL != sigpipe) 163 if (NULL != sigpipe)
157 return; /* already initialized */ 164 return; /* already initialized */
158 sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE); 165 sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE);
159 GNUNET_assert (sigpipe != NULL); 166 GNUNET_assert (sigpipe != NULL);
160 shc_chld = 167 shc_chld =
161 GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death); 168 GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
169 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
170 "Child management started.\n");
162} 171}
163 172
173/**
174 * Clean up.
175 */
176// void __attribute__ ((destructor))
177static void
178child_management_done ()
179{
180 GNUNET_assert (NULL == sig_task);
181 GNUNET_SIGNAL_handler_uninstall (shc_chld);
182 shc_chld = NULL;
183 GNUNET_DISK_pipe_close (sigpipe);
184 sigpipe = NULL;
185 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
186 "Child management stopped.\n");
187}
164 188
165struct GNUNET_ChildWaitHandle * 189struct GNUNET_ChildWaitHandle *
166GNUNET_wait_child (struct GNUNET_OS_Process *proc, 190GNUNET_wait_child (struct GNUNET_OS_Process *proc,
@@ -189,7 +213,6 @@ GNUNET_wait_child (struct GNUNET_OS_Process *proc,
189 return cwh; 213 return cwh;
190} 214}
191 215
192
193void 216void
194GNUNET_wait_child_cancel (struct GNUNET_ChildWaitHandle *cwh) 217GNUNET_wait_child_cancel (struct GNUNET_ChildWaitHandle *cwh)
195{ 218{
@@ -198,22 +221,9 @@ GNUNET_wait_child_cancel (struct GNUNET_ChildWaitHandle *cwh)
198 cwh); 221 cwh);
199 if (NULL == cwh_head) 222 if (NULL == cwh_head)
200 { 223 {
224 child_management_done ();
201 GNUNET_SCHEDULER_cancel (sig_task); 225 GNUNET_SCHEDULER_cancel (sig_task);
202 sig_task = NULL; 226 sig_task = NULL;
203 } 227 }
204 GNUNET_free (cwh); 228 GNUNET_free (cwh);
205} 229}
206
207
208/**
209 * Clean up.
210 */
211void __attribute__ ((destructor))
212GNUNET_CM_done ()
213{
214 GNUNET_assert (NULL == sig_task);
215 GNUNET_SIGNAL_handler_uninstall (shc_chld);
216 shc_chld = NULL;
217 GNUNET_DISK_pipe_close (sigpipe);
218 sigpipe = NULL;
219}