aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/include/gnunet_testbed_service.h21
-rw-r--r--src/testbed/gnunet-service-testbed.c45
-rw-r--r--src/testbed/testbed_api.c111
-rw-r--r--src/testbed/testbed_api_hosts.c86
-rw-r--r--src/testbed/testbed_api_hosts.h26
5 files changed, 171 insertions, 118 deletions
diff --git a/src/include/gnunet_testbed_service.h b/src/include/gnunet_testbed_service.h
index 6b50efe97..a3f092172 100644
--- a/src/include/gnunet_testbed_service.h
+++ b/src/include/gnunet_testbed_service.h
@@ -88,6 +88,26 @@ GNUNET_TESTBED_host_create (const char *hostname,
88 uint16_t port); 88 uint16_t port);
89 89
90 90
91
92/**
93 * Create a host to run peers and controllers on. This function is used
94 * if a peer learns about a host via IPC between controllers (and thus
95 * some higher-level controller has already determined the unique IDs).
96 *
97 * @param id global host ID assigned to the host; 0 is
98 * reserved to always mean 'localhost'
99 * @param hostname name of the host, use "NULL" for localhost
100 * @param username username to use for the login; may be NULL
101 * @param port port number to use for ssh; use 0 to let ssh decide
102 * @return handle to the host, NULL on error
103 */
104struct GNUNET_TESTBED_Host *
105GNUNET_TESTBED_host_create_with_id (uint32_t id,
106 const char *hostname,
107 const char *username,
108 uint16_t port);
109
110
91/** 111/**
92 * Load a set of hosts from a configuration file. 112 * Load a set of hosts from a configuration file.
93 * 113 *
@@ -785,7 +805,6 @@ GNUNET_TESTBED_overlay_configure_topology (void *op_cls,
785 ...); 805 ...);
786 806
787 807
788
789/** 808/**
790 * Ask the testbed controller to write the current overlay topology to 809 * Ask the testbed controller to write the current overlay topology to
791 * a file. Naturally, the file will only contain a snapshot as the 810 * a file. Naturally, the file will only contain a snapshot as the
diff --git a/src/testbed/gnunet-service-testbed.c b/src/testbed/gnunet-service-testbed.c
index 665af9d3a..327daf584 100644
--- a/src/testbed/gnunet-service-testbed.c
+++ b/src/testbed/gnunet-service-testbed.c
@@ -55,6 +55,11 @@ struct Context
55 55
56 56
57/** 57/**
58 * Wrapped stdin.
59 */
60static struct GNUNET_DISK_FileHandle *fh;
61
62/**
58 * The master context; generated with the first INIT message 63 * The master context; generated with the first INIT message
59 */ 64 */
60static struct Context *master_context; 65static struct Context *master_context;
@@ -139,8 +144,13 @@ handle_addhost (void *cls,
139 host = GNUNET_TESTBED_host_create (hostname, username, ntohs 144 host = GNUNET_TESTBED_host_create (hostname, username, ntohs
140 (msg->ssh_port)); 145 (msg->ssh_port));
141 /* Store host in a hashmap? But the host_id will be different */ 146 /* Store host in a hashmap? But the host_id will be different */
147 /* hashmap? maybe array? 4-8 bytes/host and O(1) lookup vs.
148 > 80 bytes for hash map with slightly worse lookup; only
149 if we really get a tiny fraction of the hosts, the hash
150 map would result in any savings... (GNUNET_array_grow) */
142} 151}
143 152
153
144/** 154/**
145 * Task to clean up and shutdown nicely 155 * Task to clean up and shutdown nicely
146 * 156 *
@@ -151,8 +161,16 @@ static void
151shutdown_task (void *cls, 161shutdown_task (void *cls,
152 const struct GNUNET_SCHEDULER_TaskContext *tc) 162 const struct GNUNET_SCHEDULER_TaskContext *tc)
153{ 163{
164 shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
165 GNUNET_SCHEDULER_shutdown ();
154 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n"); 166 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
167 if (NULL != fh)
168 {
169 GNUNET_DISK_file_close (fh);
170 fh = NULL;
171 }
155 GNUNET_free_non_null (master_context); 172 GNUNET_free_non_null (master_context);
173 master_context = NULL;
156} 174}
157 175
158 176
@@ -171,9 +189,12 @@ client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
171 { 189 {
172 LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n"); 190 LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
173 GNUNET_SERVER_client_drop (client); 191 GNUNET_SERVER_client_drop (client);
174 GNUNET_SCHEDULER_cancel (shutdown_task_id); 192 /* should not be needed as we're terminated by failure to read
175 shutdown_task_id = 193 from stdin, but if stdin fails for some reason, this shouldn't
176 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); 194 hurt for now --- might need to revise this later if we ever
195 decide that master connections might be temporarily down
196 for some reason */
197 GNUNET_SCHEDULER_shutdown ();
177 } 198 }
178} 199}
179 200
@@ -202,11 +223,19 @@ testbed_run (void *cls,
202 message_handlers); 223 message_handlers);
203 GNUNET_SERVER_disconnect_notify (server, 224 GNUNET_SERVER_disconnect_notify (server,
204 &client_disconnect_cb, 225 &client_disconnect_cb,
205 NULL); 226 NULL);
206 shutdown_task_id = 227 fh = GNUNET_DISK_get_handle_from_native (stdin);
207 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, 228 if (NULL == fh)
208 &shutdown_task, 229 shutdown_task_id =
209 NULL); 230 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
231 &shutdown_task,
232 NULL);
233 else
234 shutdown_task_id =
235 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
236 fh,
237 &shutdown_task,
238 NULL);
210} 239}
211 240
212 241
diff --git a/src/testbed/testbed_api.c b/src/testbed/testbed_api.c
index 5d34640fa..3f49890c4 100644
--- a/src/testbed/testbed_api.c
+++ b/src/testbed/testbed_api.c
@@ -123,9 +123,37 @@ struct GNUNET_TESTBED_Controller
123 * The controller event mask 123 * The controller event mask
124 */ 124 */
125 uint64_t event_mask; 125 uint64_t event_mask;
126
127 /**
128 * Did we start the receive loop yet?
129 */
130 int in_receive;
126}; 131};
127 132
128 133
134
135/**
136 * Handler for messages from controller (testbed service)
137 *
138 * @param cls the controller handler
139 * @param msg message received, NULL on timeout or fatal error
140 */
141static void
142message_handler (void *cls, const struct GNUNET_MessageHeader *msg)
143{
144 struct GNUNET_TESTBED_Controller *c = cls;
145
146 /* FIXME: Add checks for message integrity */
147 switch (ntohs (msg->type))
148 {
149 default:
150 GNUNET_break (0);
151 }
152 GNUNET_CLIENT_receive (c->client, &message_handler, c,
153 GNUNET_TIME_UNIT_FOREVER_REL);
154}
155
156
129/** 157/**
130 * Function called to notify a client about the connection begin ready to queue 158 * Function called to notify a client about the connection begin ready to queue
131 * more data. "buf" will be NULL and "size" zero if the connection was closed 159 * more data. "buf" will be NULL and "size" zero if the connection was closed
@@ -159,6 +187,13 @@ transmit_ready_notify (void *cls, size_t size, void *buf)
159 GNUNET_TIME_UNIT_FOREVER_REL, 187 GNUNET_TIME_UNIT_FOREVER_REL,
160 GNUNET_NO, &transmit_ready_notify, 188 GNUNET_NO, &transmit_ready_notify,
161 c); 189 c);
190 if ( (GNUNET_NO == c->in_receive) &&
191 (size > 0) )
192 {
193 c->in_receive = GNUNET_YES;
194 GNUNET_CLIENT_receive (c->client, &message_handler, c,
195 GNUNET_TIME_UNIT_FOREVER_REL);
196 }
162 return size; 197 return size;
163} 198}
164 199
@@ -198,61 +233,6 @@ queue_message (struct GNUNET_TESTBED_Controller *controller,
198 233
199 234
200/** 235/**
201 * Handler for messages from controller (testbed service)
202 *
203 * @param cls the controller handler
204 * @param msg message received, NULL on timeout or fatal error
205 */
206static void
207message_handler (void *cls, const struct GNUNET_MessageHeader *msg)
208{
209 struct GNUNET_TESTBED_Controller *c = cls;
210
211 /* FIXME: Add checks for message integrity */
212 switch (ntohs (msg->type))
213 {
214 default:
215 GNUNET_break (0);
216 }
217 GNUNET_CLIENT_receive (c->client, &message_handler, c,
218 GNUNET_TIME_UNIT_FOREVER_REL);
219}
220
221
222/**
223 * ?Callback for messages recevied from server?
224 *
225 * Do not call GNUNET_SERVER_mst_destroy in callback
226 *
227 * @param cls closure
228 * @param client identification of the client
229 * @param message the actual message
230 *
231 * @return GNUNET_OK on success, GNUNET_SYSERR to stop further processing
232 */
233static int
234server_mst_cb (void *cls, void *client,
235 const struct GNUNET_MessageHeader *message)
236{
237 struct GNUNET_TESTBED_Controller *c = cls;
238 struct GNUNET_TESTBED_InitMessage *msg;
239
240 c->client = GNUNET_CLIENT_connect ("testbed", c->cfg);
241 if (NULL == c->client)
242 return GNUNET_SYSERR; /* FIXME: Call controller startup_cb ? */
243 GNUNET_CLIENT_receive (c->client, &message_handler, c,
244 GNUNET_TIME_UNIT_FOREVER_REL);
245 msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_InitMessage));
246 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_INIT);
247 msg->header.size = htons (sizeof (struct GNUNET_TESTBED_InitMessage));
248 msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (c->host));
249 msg->event_mask = GNUNET_htonll (c->event_mask);
250 queue_message (c, (struct GNUNET_MessageHeader *) msg);
251 return GNUNET_OK;
252}
253
254
255/**
256 * Start a controller process using the given configuration at the 236 * Start a controller process using the given configuration at the
257 * given host. 237 * given host.
258 * 238 *
@@ -279,9 +259,10 @@ GNUNET_TESTBED_controller_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
279 "gnunet-service-testbed", 259 "gnunet-service-testbed",
280 NULL 260 NULL
281 }; 261 };
262 struct GNUNET_TESTBED_InitMessage *msg;
263
282 controller = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Controller)); 264 controller = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Controller));
283 controller->helper = GNUNET_TESTBED_host_run_ (host, binary_argv, 265 controller->helper = GNUNET_TESTBED_host_run_ (host, binary_argv);
284 &server_mst_cb, controller);
285 if (NULL == controller->helper) 266 if (NULL == controller->helper)
286 { 267 {
287 GNUNET_free (controller); 268 GNUNET_free (controller);
@@ -292,6 +273,18 @@ GNUNET_TESTBED_controller_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
292 controller->cc_cls = cc_cls; 273 controller->cc_cls = cc_cls;
293 controller->event_mask = event_mask; 274 controller->event_mask = event_mask;
294 controller->cfg = GNUNET_CONFIGURATION_dup (cfg); 275 controller->cfg = GNUNET_CONFIGURATION_dup (cfg);
276 controller->client = GNUNET_CLIENT_connect ("testbed", controller->cfg);
277 if (NULL == controller->client)
278 {
279 GNUNET_TESTBED_controller_stop (controller);
280 return NULL;
281 }
282 msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_InitMessage));
283 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_INIT);
284 msg->header.size = htons (sizeof (struct GNUNET_TESTBED_InitMessage));
285 msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (controller->host));
286 msg->event_mask = GNUNET_htonll (controller->event_mask);
287 queue_message (controller, (struct GNUNET_MessageHeader *) msg);
295 return controller; 288 return controller;
296} 289}
297 290
@@ -338,7 +331,8 @@ GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_Controller *controller)
338 GNUNET_free (mq_entry->msg); 331 GNUNET_free (mq_entry->msg);
339 GNUNET_free (mq_entry); 332 GNUNET_free (mq_entry);
340 } 333 }
341 GNUNET_CLIENT_disconnect (controller->client); 334 if (NULL != controller->client)
335 GNUNET_CLIENT_disconnect (controller->client);
342 GNUNET_TESTBED_host_stop_ (controller->helper); 336 GNUNET_TESTBED_host_stop_ (controller->helper);
343 GNUNET_CONFIGURATION_destroy (controller->cfg); 337 GNUNET_CONFIGURATION_destroy (controller->cfg);
344 GNUNET_free (controller); 338 GNUNET_free (controller);
@@ -391,6 +385,7 @@ void
391GNUNET_TESTBED_overlay_write_topology_to_file (struct GNUNET_TESTBED_Controller *controller, 385GNUNET_TESTBED_overlay_write_topology_to_file (struct GNUNET_TESTBED_Controller *controller,
392 const char *filename) 386 const char *filename)
393{ 387{
388 GNUNET_break (0);
394} 389}
395 390
396 391
diff --git a/src/testbed/testbed_api_hosts.c b/src/testbed/testbed_api_hosts.c
index a12d6ce11..c4dfcf3c9 100644
--- a/src/testbed/testbed_api_hosts.c
+++ b/src/testbed/testbed_api_hosts.c
@@ -132,7 +132,7 @@ GNUNET_TESTBED_host_create_by_id_ (uint32_t id)
132uint32_t 132uint32_t
133GNUNET_TESTBED_host_get_id_ (const struct GNUNET_TESTBED_Host *host) 133GNUNET_TESTBED_host_get_id_ (const struct GNUNET_TESTBED_Host *host)
134{ 134{
135 return host->unique_id; 135 return host->unique_id;
136} 136}
137 137
138 138
@@ -147,10 +147,10 @@ GNUNET_TESTBED_host_get_id_ (const struct GNUNET_TESTBED_Host *host)
147 * @return handle to the host, NULL on error 147 * @return handle to the host, NULL on error
148 */ 148 */
149struct GNUNET_TESTBED_Host * 149struct GNUNET_TESTBED_Host *
150GNUNET_TESTBED_host_create_with_id_ (uint32_t id, 150GNUNET_TESTBED_host_create_with_id (uint32_t id,
151 const char *hostname, 151 const char *hostname,
152 const char *username, 152 const char *username,
153 uint16_t port) 153 uint16_t port)
154{ 154{
155 struct GNUNET_TESTBED_Host *host; 155 struct GNUNET_TESTBED_Host *host;
156 156
@@ -180,10 +180,10 @@ GNUNET_TESTBED_host_create (const char *hostname,
180 static uint32_t uid_generator; 180 static uint32_t uid_generator;
181 181
182 if (NULL == hostname) 182 if (NULL == hostname)
183 return GNUNET_TESTBED_host_create_with_id_ (0, hostname, username, port); 183 return GNUNET_TESTBED_host_create_with_id (0, hostname, username, port);
184 return GNUNET_TESTBED_host_create_with_id_ (++uid_generator, 184 return GNUNET_TESTBED_host_create_with_id (++uid_generator,
185 hostname, username, 185 hostname, username,
186 port); 186 port);
187} 187}
188 188
189 189
@@ -198,6 +198,7 @@ unsigned int
198GNUNET_TESTBED_hosts_load_from_file (const char *filename, 198GNUNET_TESTBED_hosts_load_from_file (const char *filename,
199 struct GNUNET_TESTBED_Host **hosts) 199 struct GNUNET_TESTBED_Host **hosts)
200{ 200{
201 // see testing_group.c, GNUNET_TESTING_hosts_load
201 GNUNET_break (0); 202 GNUNET_break (0);
202 return 0; 203 return 0;
203} 204}
@@ -223,9 +224,14 @@ GNUNET_TESTBED_host_destroy (struct GNUNET_TESTBED_Host *host)
223struct GNUNET_TESTBED_HelperHandle 224struct GNUNET_TESTBED_HelperHandle
224{ 225{
225 /** 226 /**
226 * The helper handle 227 * The process handle
227 */ 228 */
228 struct GNUNET_HELPER_Handle *handle; 229 struct GNUNET_OS_Process *process;
230
231 /**
232 * Pipe connecting to stdin of the process.
233 */
234 struct GNUNET_DISK_PipeHandle *cpipe;
229 235
230 /** 236 /**
231 * The port number for ssh; used for helpers starting ssh 237 * The port number for ssh; used for helpers starting ssh
@@ -247,39 +253,62 @@ struct GNUNET_TESTBED_HelperHandle
247 * 253 *
248 * @param host host to use, use "NULL" for localhost 254 * @param host host to use, use "NULL" for localhost
249 * @param binary_argv binary name and command-line arguments to give to the binary 255 * @param binary_argv binary name and command-line arguments to give to the binary
250 * @param cb function to call for messages received from the binary
251 * @param cb_cls closure for cb
252 * @return handle to terminate the command, NULL on error 256 * @return handle to terminate the command, NULL on error
253 */ 257 */
254struct GNUNET_TESTBED_HelperHandle * 258struct GNUNET_TESTBED_HelperHandle *
255GNUNET_TESTBED_host_run_ (struct GNUNET_TESTBED_Host *host, 259GNUNET_TESTBED_host_run_ (const struct GNUNET_TESTBED_Host *host,
256 char *const binary_argv[], 260 char *const binary_argv[])
257 GNUNET_SERVER_MessageTokenizerCallback cb, void *cb_cls)
258{ 261{
259 /* FIXME: decide on the SSH command line, prepend it and
260 run GNUNET_HELPER_start with the modified binary_name and binary_argv! */
261 struct GNUNET_TESTBED_HelperHandle *h; 262 struct GNUNET_TESTBED_HelperHandle *h;
262 char *const local_args[] = {NULL}; 263 unsigned int argc;
263 264
265 argc = 0;
266 while (NULL != binary_argv[argc])
267 argc++;
264 h = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_HelperHandle)); 268 h = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_HelperHandle));
269 h->cpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_YES, GNUNET_NO);
265 if (0 == host->unique_id) 270 if (0 == host->unique_id)
266 { 271 {
267 h->handle = GNUNET_HELPER_start ("gnunet-service-testbed", local_args, 272 h->process = GNUNET_OS_start_process_vap (GNUNET_YES,
268 cb, cb_cls); 273 h->cpipe, NULL,
274 "gnunet-service-testbed",
275 binary_argv);
269 } 276 }
270 else 277 else
271 { 278 {
279 char *remote_args[argc + 6 + 1];
280 unsigned int argp;
281
272 GNUNET_asprintf (&h->port, "%d", host->port); 282 GNUNET_asprintf (&h->port, "%d", host->port);
273 GNUNET_asprintf (&h->dst, "%s@%s", host->hostname, host->username); 283 GNUNET_asprintf (&h->dst, "%s@%s", host->hostname, host->username);
274 char *remote_args[] = {"ssh", "-p", h->port, "-q", h->dst, 284 argp = 0;
275 "gnunet-service-testbed", NULL}; 285 remote_args[argp++] = "ssh";
276 h->handle = GNUNET_HELPER_start ("ssh", remote_args, cb, cb_cls); 286 remote_args[argp++] = "-p";
287 remote_args[argp++] = h->port;
288 remote_args[argp++] = "-q";
289 remote_args[argp++] = h->dst;
290 remote_args[argp++] = "gnunet-service-testbed";
291 while (NULL != binary_argv[argp-6])
292 {
293 remote_args[argp] = binary_argv[argp - 6];
294 argp++;
295 }
296 remote_args[argp++] = NULL;
297 GNUNET_assert (argp == argc + 6 + 1);
298 h->process = GNUNET_OS_start_process_vap (GNUNET_YES,
299 h->cpipe, NULL,
300 "ssh",
301 remote_args);
277 } 302 }
278 if (NULL == h->handle) 303 if (NULL == h->process)
279 { 304 {
305 GNUNET_break (GNUNET_OK == GNUNET_DISK_pipe_close (h->cpipe));
306 GNUNET_free_non_null (h->port);
307 GNUNET_free_non_null (h->dst);
280 GNUNET_free (h); 308 GNUNET_free (h);
281 return NULL; 309 return NULL;
282 } 310 }
311 GNUNET_break (GNUNET_OK == GNUNET_DISK_pipe_close_end (h->cpipe, GNUNET_DISK_PIPE_END_READ));
283 return h; 312 return h;
284} 313}
285 314
@@ -292,7 +321,10 @@ GNUNET_TESTBED_host_run_ (struct GNUNET_TESTBED_Host *host,
292void 321void
293GNUNET_TESTBED_host_stop_ (struct GNUNET_TESTBED_HelperHandle *handle) 322GNUNET_TESTBED_host_stop_ (struct GNUNET_TESTBED_HelperHandle *handle)
294{ 323{
295 GNUNET_HELPER_stop (handle->handle); 324 GNUNET_break (GNUNET_OK == GNUNET_DISK_pipe_close (handle->cpipe));
325 GNUNET_break (0 == GNUNET_OS_process_kill (handle->process, SIGTERM));
326 GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (handle->process));
327 GNUNET_OS_process_destroy (handle->process);
296 GNUNET_free_non_null (handle->port); 328 GNUNET_free_non_null (handle->port);
297 GNUNET_free_non_null (handle->dst); 329 GNUNET_free_non_null (handle->dst);
298 GNUNET_free (handle); 330 GNUNET_free (handle);
diff --git a/src/testbed/testbed_api_hosts.h b/src/testbed/testbed_api_hosts.h
index 0c36da0ee..eaf2a4d11 100644
--- a/src/testbed/testbed_api_hosts.h
+++ b/src/testbed/testbed_api_hosts.h
@@ -55,25 +55,6 @@ GNUNET_TESTBED_host_create_by_id_ (uint32_t id);
55 55
56 56
57/** 57/**
58 * Create a host to run peers and controllers on. This function is used
59 * if a peer learns about a host via IPC between controllers (and thus
60 * some higher-level controller has already determined the unique IDs).
61 *
62 * @param id global host ID assigned to the host; 0 is
63 * reserved to always mean 'localhost'
64 * @param hostname name of the host, use "NULL" for localhost
65 * @param username username to use for the login; may be NULL
66 * @param port port number to use for ssh; use 0 to let ssh decide
67 * @return handle to the host, NULL on error
68 */
69struct GNUNET_TESTBED_Host *
70GNUNET_TESTBED_host_create_with_id_ (uint32_t id,
71 const char *hostname,
72 const char *username,
73 uint16_t port);
74
75
76/**
77 * Obtain a host's unique global ID. 58 * Obtain a host's unique global ID.
78 * 59 *
79 * @param host handle to the host, NULL means 'localhost' 60 * @param host handle to the host, NULL means 'localhost'
@@ -98,14 +79,11 @@ struct GNUNET_TESTBED_HelperHandle;
98 * 79 *
99 * @param host host to use, use "NULL" for localhost 80 * @param host host to use, use "NULL" for localhost
100 * @param binary_argv binary name and command-line arguments to give to the binary 81 * @param binary_argv binary name and command-line arguments to give to the binary
101 * @param cb function to call for messages received from the binary
102 * @param cb_cls closure for cb
103 * @return handle to terminate the command, NULL on error 82 * @return handle to terminate the command, NULL on error
104 */ 83 */
105struct GNUNET_TESTBED_HelperHandle * 84struct GNUNET_TESTBED_HelperHandle *
106GNUNET_TESTBED_host_run_ (struct GNUNET_TESTBED_Host *host, 85GNUNET_TESTBED_host_run_ (const struct GNUNET_TESTBED_Host *host,
107 char *const binary_argv[], 86 char *const binary_argv[]);
108 GNUNET_SERVER_MessageTokenizerCallback cb, void *cb_cls);
109 87
110 88
111/** 89/**