diff options
Diffstat (limited to 'src/lib/testing/testing.c')
-rw-r--r-- | src/lib/testing/testing.c | 2830 |
1 files changed, 2830 insertions, 0 deletions
diff --git a/src/lib/testing/testing.c b/src/lib/testing/testing.c new file mode 100644 index 000000000..fdfa80d87 --- /dev/null +++ b/src/lib/testing/testing.c | |||
@@ -0,0 +1,2830 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2008, 2009, 2012 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.c | ||
23 | * @brief convenience API for writing testcases for GNUnet | ||
24 | * Many testcases need to start and stop a peer/service | ||
25 | * and this library is supposed to make that easier | ||
26 | * for TESTCASES. Normal programs should always | ||
27 | * use functions from gnunet_{util,arm}_lib.h. This API is | ||
28 | * ONLY for writing testcases (or internal use of the testbed). | ||
29 | * @author Christian Grothoff | ||
30 | * | ||
31 | */ | ||
32 | #include "platform.h" | ||
33 | #include "gnunet_util_lib.h" | ||
34 | #include "gnunet_arm_service.h" | ||
35 | #include "gnunet_testing_lib.h" | ||
36 | #include "gnunet_testing_ng_lib.h" | ||
37 | #include "gnunet_testing_plugin.h" | ||
38 | #include "gnunet_testing_barrier.h" | ||
39 | #include "gnunet_testing_netjail_lib.h" | ||
40 | #include "testing_cmds.h" | ||
41 | |||
42 | #define LOG(kind, ...) GNUNET_log_from (kind, "testing-api", __VA_ARGS__) | ||
43 | |||
44 | #define CONNECT_ADDRESS_TEMPLATE "%s-192.168.15.%u" | ||
45 | |||
46 | #define ROUTER_CONNECT_ADDRESS_TEMPLATE "%s-92.68.150.%u" | ||
47 | |||
48 | #define KNOWN_CONNECT_ADDRESS_TEMPLATE "%s-92.68.151.%u" | ||
49 | |||
50 | /* Use the IP addresses below instead of the public ones, | ||
51 | * if the start script was not started from within a new namespace | ||
52 | * created by unshare. The UPNP test case needs public IP | ||
53 | * addresse for miniupnpd to function. | ||
54 | * FIXME We should introduce a switch indicating if public | ||
55 | * addresses should be used or not. This info has to be | ||
56 | * propagated from the start script to the c code. | ||
57 | #define ROUTER_CONNECT_ADDRESS_TEMPLATE "%s-172.16.150.%u" | ||
58 | |||
59 | #define KNOWN_CONNECT_ADDRESS_TEMPLATE "%s-172.16.151.%u" | ||
60 | */ | ||
61 | |||
62 | #define PREFIX_TCP "tcp" | ||
63 | |||
64 | #define PREFIX_UDP "udp" | ||
65 | |||
66 | #define PREFIX_TCP_NATTED "tcp_natted" | ||
67 | |||
68 | #define PREFIX_UDP_NATTED "udp_natted" | ||
69 | |||
70 | /** | ||
71 | * Lowest port used for GNUnet testing. Should be high enough to not | ||
72 | * conflict with other applications running on the hosts but be low | ||
73 | * enough to not conflict with client-ports (typically starting around | ||
74 | * 32k). | ||
75 | */ | ||
76 | #define LOW_PORT 12000 | ||
77 | |||
78 | /** | ||
79 | * Highest port used for GNUnet testing. Should be low enough to not | ||
80 | * conflict with the port range for "local" ports (client apps; see | ||
81 | * /proc/sys/net/ipv4/ip_local_port_range on Linux for example). | ||
82 | */ | ||
83 | #define HIGH_PORT 56000 | ||
84 | |||
85 | |||
86 | struct SharedServiceInstance | ||
87 | { | ||
88 | struct SharedService *ss; | ||
89 | |||
90 | char *cfg_fn; | ||
91 | |||
92 | struct GNUNET_OS_Process *proc; | ||
93 | |||
94 | char *unix_sock; | ||
95 | |||
96 | char *port_str; | ||
97 | |||
98 | unsigned int n_refs; | ||
99 | }; | ||
100 | |||
101 | struct SharedService | ||
102 | { | ||
103 | char *sname; | ||
104 | |||
105 | struct SharedServiceInstance **instances; | ||
106 | |||
107 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
108 | |||
109 | unsigned int n_peers; | ||
110 | |||
111 | unsigned int share; | ||
112 | |||
113 | unsigned int n_instances; | ||
114 | }; | ||
115 | |||
116 | |||
117 | /** | ||
118 | * Handle for a system on which GNUnet peers are executed; | ||
119 | * a system is used for reserving unique paths and ports. | ||
120 | */ | ||
121 | struct GNUNET_TESTING_System | ||
122 | { | ||
123 | /** | ||
124 | * Prefix (e.g. "/tmp/gnunet-testing/") we prepend to each | ||
125 | * GNUNET_HOME. | ||
126 | */ | ||
127 | char *tmppath; | ||
128 | |||
129 | /** | ||
130 | * The trusted ip. Can either be a single ip address or a network address in | ||
131 | * CIDR notation. | ||
132 | */ | ||
133 | char *trusted_ip; | ||
134 | |||
135 | /** | ||
136 | * our hostname | ||
137 | */ | ||
138 | char *hostname; | ||
139 | |||
140 | /** | ||
141 | * Hostkeys data, contains "GNUNET_TESTING_HOSTKEYFILESIZE * total_hostkeys" bytes. | ||
142 | */ | ||
143 | char *hostkeys_data; | ||
144 | |||
145 | /** | ||
146 | * memory map for @e hostkeys_data. | ||
147 | */ | ||
148 | struct GNUNET_DISK_MapHandle *map; | ||
149 | |||
150 | struct SharedService *shared_services; | ||
151 | |||
152 | unsigned int n_shared_services; | ||
153 | |||
154 | /** | ||
155 | * Bitmap where each port that has already been reserved for some GNUnet peer | ||
156 | * is recorded. Note that we make no distinction between TCP and UDP ports | ||
157 | * and test if a port is already in use before assigning it to a peer/service. | ||
158 | * If we detect that a port is already in use, we also mark it in this bitmap. | ||
159 | * So all the bits that are zero merely indicate ports that MIGHT be available | ||
160 | * for peers. | ||
161 | */ | ||
162 | uint32_t reserved_ports[65536 / 32]; | ||
163 | |||
164 | /** | ||
165 | * Counter we use to make service home paths unique on this system; | ||
166 | * the full path consists of the tmppath and this number. Each | ||
167 | * UNIXPATH for a peer is also modified to include the respective | ||
168 | * path counter to ensure uniqueness. This field is incremented | ||
169 | * by one for each configured peer. Even if peers are destroyed, | ||
170 | * we never re-use path counters. | ||
171 | */ | ||
172 | uint32_t path_counter; | ||
173 | |||
174 | /** | ||
175 | * The number of hostkeys | ||
176 | */ | ||
177 | uint32_t total_hostkeys; | ||
178 | |||
179 | /** | ||
180 | * Lowest port we are allowed to use. | ||
181 | */ | ||
182 | uint16_t lowport; | ||
183 | |||
184 | /** | ||
185 | * Highest port we are allowed to use. | ||
186 | */ | ||
187 | uint16_t highport; | ||
188 | }; | ||
189 | |||
190 | |||
191 | /** | ||
192 | * Handle for a GNUnet peer controlled by testing. | ||
193 | */ | ||
194 | struct GNUNET_TESTING_Peer | ||
195 | { | ||
196 | /** | ||
197 | * The TESTING system associated with this peer | ||
198 | */ | ||
199 | struct GNUNET_TESTING_System *system; | ||
200 | |||
201 | /** | ||
202 | * Path to the configuration file for this peer. | ||
203 | */ | ||
204 | char *cfgfile; | ||
205 | |||
206 | /** | ||
207 | * Binary to be executed during 'GNUNET_TESTING_peer_start'. | ||
208 | * Typically 'gnunet-service-arm' (but can be set to a | ||
209 | * specific service by 'GNUNET_TESTING_service_run' if | ||
210 | * necessary). | ||
211 | */ | ||
212 | char *main_binary; | ||
213 | char *args; | ||
214 | |||
215 | /** | ||
216 | * Handle to the running binary of the service, NULL if the | ||
217 | * peer/service is currently not running. | ||
218 | */ | ||
219 | struct GNUNET_OS_Process *main_process; | ||
220 | |||
221 | /** | ||
222 | * The handle to the peer's ARM service | ||
223 | */ | ||
224 | struct GNUNET_ARM_Handle *ah; | ||
225 | |||
226 | /** | ||
227 | * The config of the peer | ||
228 | */ | ||
229 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
230 | |||
231 | /** | ||
232 | * The callback to call asynchronously when a peer is stopped | ||
233 | */ | ||
234 | GNUNET_TESTING_PeerStopCallback cb; | ||
235 | |||
236 | /** | ||
237 | * The closure for the above callback | ||
238 | */ | ||
239 | void *cb_cls; | ||
240 | |||
241 | /** | ||
242 | * The cached identity of this peer. Will be populated on call to | ||
243 | * GNUNET_TESTING_peer_get_identity() | ||
244 | */ | ||
245 | struct GNUNET_PeerIdentity *id; | ||
246 | |||
247 | struct SharedServiceInstance **ss_instances; | ||
248 | |||
249 | /** | ||
250 | * Array of ports currently allocated to this peer. These ports will be | ||
251 | * released upon peer destroy and can be used by other peers which are | ||
252 | * configured after. | ||
253 | */ | ||
254 | uint16_t *ports; | ||
255 | |||
256 | /** | ||
257 | * The number of ports in the above array | ||
258 | */ | ||
259 | unsigned int nports; | ||
260 | |||
261 | /** | ||
262 | * The keynumber of this peer's hostkey | ||
263 | */ | ||
264 | uint32_t key_number; | ||
265 | }; | ||
266 | |||
267 | |||
268 | /** | ||
269 | * Testing includes a number of pre-created hostkeys for faster peer | ||
270 | * startup. This function loads such keys into memory from a file. | ||
271 | * | ||
272 | * @param system the testing system handle | ||
273 | * @return #GNUNET_OK on success; #GNUNET_SYSERR on error | ||
274 | */ | ||
275 | static enum GNUNET_GenericReturnValue | ||
276 | hostkeys_load (struct GNUNET_TESTING_System *system) | ||
277 | { | ||
278 | uint64_t fs; | ||
279 | char *data_dir; | ||
280 | char *filename; | ||
281 | struct GNUNET_DISK_FileHandle *fd; | ||
282 | |||
283 | GNUNET_assert (NULL == system->hostkeys_data); | ||
284 | data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR); | ||
285 | GNUNET_asprintf (&filename, "%s/testing_hostkeys.ecc", data_dir); | ||
286 | GNUNET_free (data_dir); | ||
287 | |||
288 | if (GNUNET_YES != GNUNET_DISK_file_test (filename)) | ||
289 | { | ||
290 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
291 | _ ("Hostkeys file not found: %s\n"), | ||
292 | filename); | ||
293 | GNUNET_free (filename); | ||
294 | return GNUNET_SYSERR; | ||
295 | } | ||
296 | /* Check hostkey file size, read entire thing into memory */ | ||
297 | if (GNUNET_OK != | ||
298 | GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES)) | ||
299 | fs = 0; | ||
300 | if (0 == fs) | ||
301 | { | ||
302 | GNUNET_free (filename); | ||
303 | return GNUNET_SYSERR; /* File is empty */ | ||
304 | } | ||
305 | if (0 != (fs % GNUNET_TESTING_HOSTKEYFILESIZE)) | ||
306 | { | ||
307 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
308 | _ ("Incorrect hostkey file format: %s\n"), | ||
309 | filename); | ||
310 | GNUNET_free (filename); | ||
311 | return GNUNET_SYSERR; | ||
312 | } | ||
313 | fd = GNUNET_DISK_file_open (filename, | ||
314 | GNUNET_DISK_OPEN_READ, | ||
315 | GNUNET_DISK_PERM_NONE); | ||
316 | if (NULL == fd) | ||
317 | { | ||
318 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename); | ||
319 | GNUNET_free (filename); | ||
320 | return GNUNET_SYSERR; | ||
321 | } | ||
322 | GNUNET_free (filename); | ||
323 | system->hostkeys_data = | ||
324 | GNUNET_DISK_file_map (fd, &system->map, GNUNET_DISK_MAP_TYPE_READ, fs); | ||
325 | GNUNET_DISK_file_close (fd); | ||
326 | if (NULL == system->hostkeys_data) | ||
327 | return GNUNET_SYSERR; | ||
328 | system->total_hostkeys = fs / GNUNET_TESTING_HOSTKEYFILESIZE; | ||
329 | return GNUNET_OK; | ||
330 | } | ||
331 | |||
332 | |||
333 | /** | ||
334 | * Function to remove the loaded hostkeys | ||
335 | * | ||
336 | * @param system the testing system handle | ||
337 | */ | ||
338 | static void | ||
339 | hostkeys_unload (struct GNUNET_TESTING_System *system) | ||
340 | { | ||
341 | GNUNET_break (NULL != system->hostkeys_data); | ||
342 | system->hostkeys_data = NULL; | ||
343 | GNUNET_DISK_file_unmap (system->map); | ||
344 | system->map = NULL; | ||
345 | system->hostkeys_data = NULL; | ||
346 | system->total_hostkeys = 0; | ||
347 | } | ||
348 | |||
349 | |||
350 | /** | ||
351 | * Function to iterate over options. | ||
352 | * | ||
353 | * @param cls closure | ||
354 | * @param section name of the section | ||
355 | * @param option name of the option | ||
356 | * @param value value of the option | ||
357 | */ | ||
358 | static void | ||
359 | cfg_copy_iterator (void *cls, | ||
360 | const char *section, | ||
361 | const char *option, | ||
362 | const char *value) | ||
363 | { | ||
364 | struct GNUNET_CONFIGURATION_Handle *cfg2 = cls; | ||
365 | |||
366 | GNUNET_CONFIGURATION_set_value_string (cfg2, section, option, value); | ||
367 | } | ||
368 | |||
369 | |||
370 | /** | ||
371 | * Create a system handle. There must only be one system | ||
372 | * handle per operating system. | ||
373 | * | ||
374 | * @param testdir only the directory name without any path. This is used for | ||
375 | * all service homes; the directory will be created in a temporary | ||
376 | * location depending on the underlying OS. This variable will be | ||
377 | * overridden with the value of the environmental variable | ||
378 | * GNUNET_TESTING_PREFIX, if it exists. | ||
379 | * @param trusted_ip the ip address which will be set as TRUSTED HOST in all | ||
380 | * service configurations generated to allow control connections from | ||
381 | * this ip. This can either be a single ip address or a network address | ||
382 | * in CIDR notation. | ||
383 | * @param hostname the hostname of the system we are using for testing; NULL for | ||
384 | * localhost | ||
385 | * @param shared_services NULL terminated array describing services that are to | ||
386 | * be shared among peers | ||
387 | * @param lowport lowest port number this system is allowed to allocate (inclusive) | ||
388 | * @param highport highest port number this system is allowed to allocate (exclusive) | ||
389 | * @return handle to this system, NULL on error | ||
390 | */ | ||
391 | struct GNUNET_TESTING_System * | ||
392 | GNUNET_TESTING_system_create_with_portrange ( | ||
393 | const char *testdir, | ||
394 | const char *trusted_ip, | ||
395 | const char *hostname, | ||
396 | const struct GNUNET_TESTING_SharedService *shared_services, | ||
397 | uint16_t lowport, | ||
398 | uint16_t highport) | ||
399 | { | ||
400 | struct GNUNET_TESTING_System *system; | ||
401 | struct GNUNET_TESTING_SharedService tss; | ||
402 | struct SharedService ss; | ||
403 | unsigned int cnt; | ||
404 | |||
405 | GNUNET_assert (NULL != testdir); | ||
406 | system = GNUNET_new (struct GNUNET_TESTING_System); | ||
407 | if (NULL == (system->tmppath = getenv (GNUNET_TESTING_PREFIX))) | ||
408 | system->tmppath = GNUNET_DISK_mkdtemp (testdir); | ||
409 | else | ||
410 | system->tmppath = GNUNET_strdup (system->tmppath); | ||
411 | system->lowport = lowport; | ||
412 | system->highport = highport; | ||
413 | if (NULL == system->tmppath) | ||
414 | { | ||
415 | GNUNET_free (system); | ||
416 | return NULL; | ||
417 | } | ||
418 | if (NULL != trusted_ip) | ||
419 | system->trusted_ip = GNUNET_strdup (trusted_ip); | ||
420 | if (NULL != hostname) | ||
421 | system->hostname = GNUNET_strdup (hostname); | ||
422 | if (GNUNET_OK != hostkeys_load (system)) | ||
423 | { | ||
424 | GNUNET_TESTING_system_destroy (system, GNUNET_YES); | ||
425 | return NULL; | ||
426 | } | ||
427 | if (NULL == shared_services) | ||
428 | return system; | ||
429 | for (cnt = 0; NULL != shared_services[cnt].service; cnt++) | ||
430 | { | ||
431 | tss = shared_services[cnt]; | ||
432 | memset (&ss, 0, sizeof (ss)); | ||
433 | ss.sname = GNUNET_strdup (tss.service); | ||
434 | ss.cfg = GNUNET_CONFIGURATION_create (); | ||
435 | GNUNET_CONFIGURATION_iterate_section_values (tss.cfg, | ||
436 | ss.sname, | ||
437 | &cfg_copy_iterator, | ||
438 | ss.cfg); | ||
439 | GNUNET_CONFIGURATION_iterate_section_values (tss.cfg, | ||
440 | "TESTING", | ||
441 | &cfg_copy_iterator, | ||
442 | ss.cfg); | ||
443 | GNUNET_CONFIGURATION_iterate_section_values (tss.cfg, | ||
444 | "PATHS", | ||
445 | &cfg_copy_iterator, | ||
446 | ss.cfg); | ||
447 | ss.share = tss.share; | ||
448 | GNUNET_array_append (system->shared_services, | ||
449 | system->n_shared_services, | ||
450 | ss); | ||
451 | } | ||
452 | return system; | ||
453 | } | ||
454 | |||
455 | |||
456 | /** | ||
457 | * Create a system handle. There must only be one system handle per operating | ||
458 | * system. Uses a default range for allowed ports. Ports are still tested for | ||
459 | * availability. | ||
460 | * | ||
461 | * @param testdir only the directory name without any path. This is used for all | ||
462 | * service homes; the directory will be created in a temporary location | ||
463 | * depending on the underlying OS. This variable will be | ||
464 | * overridden with the value of the environmental variable | ||
465 | * GNUNET_TESTING_PREFIX, if it exists. | ||
466 | * @param trusted_ip the ip address which will be set as TRUSTED HOST in all | ||
467 | * service configurations generated to allow control connections from | ||
468 | * this ip. This can either be a single ip address or a network address | ||
469 | * in CIDR notation. | ||
470 | * @param hostname the hostname of the system we are using for testing; NULL for | ||
471 | * localhost | ||
472 | * @param shared_services NULL terminated array describing services that are to | ||
473 | * be shared among peers | ||
474 | * @return handle to this system, NULL on error | ||
475 | */ | ||
476 | struct GNUNET_TESTING_System * | ||
477 | GNUNET_TESTING_system_create ( | ||
478 | const char *testdir, | ||
479 | const char *trusted_ip, | ||
480 | const char *hostname, | ||
481 | const struct GNUNET_TESTING_SharedService *shared_services) | ||
482 | { | ||
483 | return GNUNET_TESTING_system_create_with_portrange (testdir, | ||
484 | trusted_ip, | ||
485 | hostname, | ||
486 | shared_services, | ||
487 | LOW_PORT, | ||
488 | HIGH_PORT); | ||
489 | } | ||
490 | |||
491 | |||
492 | static void | ||
493 | cleanup_shared_service_instance (struct SharedServiceInstance *i) | ||
494 | { | ||
495 | if (NULL != i->cfg_fn) | ||
496 | { | ||
497 | (void) unlink (i->cfg_fn); | ||
498 | GNUNET_free (i->cfg_fn); | ||
499 | } | ||
500 | GNUNET_free (i->unix_sock); | ||
501 | GNUNET_free (i->port_str); | ||
502 | GNUNET_break (NULL == i->proc); | ||
503 | GNUNET_break (0 == i->n_refs); | ||
504 | GNUNET_free (i); | ||
505 | } | ||
506 | |||
507 | |||
508 | static enum GNUNET_GenericReturnValue | ||
509 | start_shared_service_instance (struct SharedServiceInstance *i) | ||
510 | { | ||
511 | char *binary; | ||
512 | char *libexec_binary; | ||
513 | |||
514 | GNUNET_assert (NULL == i->proc); | ||
515 | GNUNET_assert (NULL != i->cfg_fn); | ||
516 | (void) GNUNET_asprintf (&binary, "gnunet-service-%s", i->ss->sname); | ||
517 | libexec_binary = GNUNET_OS_get_libexec_binary_path (binary); | ||
518 | GNUNET_free (binary); | ||
519 | i->proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR, | ||
520 | NULL, | ||
521 | NULL, | ||
522 | NULL, | ||
523 | libexec_binary, | ||
524 | libexec_binary, | ||
525 | "-c", | ||
526 | i->cfg_fn, | ||
527 | NULL); | ||
528 | GNUNET_free (libexec_binary); | ||
529 | if (NULL == i->proc) | ||
530 | return GNUNET_SYSERR; | ||
531 | return GNUNET_OK; | ||
532 | } | ||
533 | |||
534 | |||
535 | static void | ||
536 | stop_shared_service_instance (struct SharedServiceInstance *i) | ||
537 | { | ||
538 | GNUNET_break (0 == i->n_refs); | ||
539 | if (0 != GNUNET_OS_process_kill (i->proc, GNUNET_TERM_SIG)) | ||
540 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
541 | "Killing shared service instance (%s) failed\n", | ||
542 | i->ss->sname); | ||
543 | (void) GNUNET_OS_process_wait (i->proc); | ||
544 | GNUNET_OS_process_destroy (i->proc); | ||
545 | i->proc = NULL; | ||
546 | } | ||
547 | |||
548 | |||
549 | /** | ||
550 | * Free system resources. | ||
551 | * | ||
552 | * @param system system to be freed | ||
553 | * @param remove_paths should the 'testdir' and all subdirectories | ||
554 | * be removed (clean up on shutdown)? | ||
555 | */ | ||
556 | void | ||
557 | GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system, | ||
558 | int remove_paths) | ||
559 | { | ||
560 | struct SharedService *ss; | ||
561 | struct SharedServiceInstance *i; | ||
562 | unsigned int ss_cnt; | ||
563 | unsigned int i_cnt; | ||
564 | |||
565 | if (NULL != system->hostkeys_data) | ||
566 | hostkeys_unload (system); | ||
567 | for (ss_cnt = 0; ss_cnt < system->n_shared_services; ss_cnt++) | ||
568 | { | ||
569 | ss = &system->shared_services[ss_cnt]; | ||
570 | for (i_cnt = 0; i_cnt < ss->n_instances; i_cnt++) | ||
571 | { | ||
572 | i = ss->instances[i_cnt]; | ||
573 | if (NULL != i->proc) | ||
574 | stop_shared_service_instance (i); | ||
575 | cleanup_shared_service_instance (i); | ||
576 | } | ||
577 | GNUNET_free (ss->instances); | ||
578 | GNUNET_CONFIGURATION_destroy (ss->cfg); | ||
579 | GNUNET_free (ss->sname); | ||
580 | } | ||
581 | GNUNET_free (system->shared_services); | ||
582 | if (GNUNET_YES == remove_paths) | ||
583 | GNUNET_DISK_directory_remove (system->tmppath); | ||
584 | GNUNET_free (system->tmppath); | ||
585 | GNUNET_free (system->trusted_ip); | ||
586 | GNUNET_free (system->hostname); | ||
587 | GNUNET_free (system); | ||
588 | } | ||
589 | |||
590 | |||
591 | /** | ||
592 | * Reserve a TCP or UDP port for a peer. | ||
593 | * | ||
594 | * @param system system to use for reservation tracking | ||
595 | * @return 0 if no free port was available | ||
596 | */ | ||
597 | uint16_t | ||
598 | GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system) | ||
599 | { | ||
600 | struct GNUNET_NETWORK_Handle *socket; | ||
601 | struct addrinfo hint; | ||
602 | struct addrinfo *ret; | ||
603 | struct addrinfo *ai; | ||
604 | uint32_t *port_buckets; | ||
605 | char *open_port_str; | ||
606 | int bind_status; | ||
607 | uint32_t xor_image; | ||
608 | uint16_t index; | ||
609 | uint16_t open_port; | ||
610 | uint16_t pos; | ||
611 | |||
612 | /* | ||
613 | FIXME: Instead of using getaddrinfo we should try to determine the port | ||
614 | status by the following heurestics. | ||
615 | |||
616 | On systems which support both IPv4 and IPv6, only ports open on both | ||
617 | address families are considered open. | ||
618 | On system with either IPv4 or IPv6. A port is considered open if it's | ||
619 | open in the respective address family | ||
620 | */hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */ | ||
621 | hint.ai_socktype = 0; | ||
622 | hint.ai_protocol = 0; | ||
623 | hint.ai_addrlen = 0; | ||
624 | hint.ai_addr = NULL; | ||
625 | hint.ai_canonname = NULL; | ||
626 | hint.ai_next = NULL; | ||
627 | hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */ | ||
628 | port_buckets = system->reserved_ports; | ||
629 | for (index = (system->lowport / 32) + 1; index < (system->highport / 32); | ||
630 | index++) | ||
631 | { | ||
632 | xor_image = (UINT32_MAX ^ port_buckets[index]); | ||
633 | if (0 == xor_image) /* Ports in the bucket are full */ | ||
634 | continue; | ||
635 | pos = system->lowport % 32; | ||
636 | while (pos < 32) | ||
637 | { | ||
638 | if (0 == ((xor_image >> pos) & 1U)) | ||
639 | { | ||
640 | pos++; | ||
641 | continue; | ||
642 | } | ||
643 | open_port = (index * 32) + pos; | ||
644 | if (open_port >= system->highport) | ||
645 | return 0; | ||
646 | GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port); | ||
647 | ret = NULL; | ||
648 | GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret)); | ||
649 | GNUNET_free (open_port_str); | ||
650 | bind_status = GNUNET_NO; | ||
651 | for (ai = ret; NULL != ai; ai = ai->ai_next) | ||
652 | { | ||
653 | socket = GNUNET_NETWORK_socket_create (ai->ai_family, SOCK_STREAM, 0); | ||
654 | if (NULL == socket) | ||
655 | continue; | ||
656 | bind_status = | ||
657 | GNUNET_NETWORK_socket_bind (socket, ai->ai_addr, ai->ai_addrlen); | ||
658 | GNUNET_NETWORK_socket_close (socket); | ||
659 | if (GNUNET_OK != bind_status) | ||
660 | break; | ||
661 | socket = GNUNET_NETWORK_socket_create (ai->ai_family, SOCK_DGRAM, 0); | ||
662 | if (NULL == socket) | ||
663 | continue; | ||
664 | bind_status = | ||
665 | GNUNET_NETWORK_socket_bind (socket, ai->ai_addr, ai->ai_addrlen); | ||
666 | GNUNET_NETWORK_socket_close (socket); | ||
667 | if (GNUNET_OK != bind_status) | ||
668 | break; | ||
669 | } | ||
670 | port_buckets[index] |= (1U << pos); /* Set the port bit */ | ||
671 | freeaddrinfo (ret); | ||
672 | if (GNUNET_OK == bind_status) | ||
673 | { | ||
674 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
675 | "Found a free port %u\n", | ||
676 | (unsigned int) open_port); | ||
677 | return open_port; | ||
678 | } | ||
679 | pos++; | ||
680 | } | ||
681 | } | ||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | |||
686 | /** | ||
687 | * Release reservation of a TCP or UDP port for a peer | ||
688 | * (used during #GNUNET_TESTING_peer_destroy()). | ||
689 | * | ||
690 | * @param system system to use for reservation tracking | ||
691 | * @param port reserved port to release | ||
692 | */ | ||
693 | void | ||
694 | GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system, | ||
695 | uint16_t port) | ||
696 | { | ||
697 | uint32_t *port_buckets; | ||
698 | uint16_t bucket; | ||
699 | uint16_t pos; | ||
700 | |||
701 | port_buckets = system->reserved_ports; | ||
702 | bucket = port / 32; | ||
703 | pos = port % 32; | ||
704 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port); | ||
705 | if (0 == (port_buckets[bucket] & (1U << pos))) | ||
706 | { | ||
707 | GNUNET_break (0); /* Port was not reserved by us using reserve_port() */ | ||
708 | return; | ||
709 | } | ||
710 | port_buckets[bucket] &= ~(1U << pos); | ||
711 | } | ||
712 | |||
713 | |||
714 | /** | ||
715 | * Testing includes a number of pre-created hostkeys for | ||
716 | * faster peer startup. This function can be used to | ||
717 | * access the n-th key of those pre-created hostkeys; note | ||
718 | * that these keys are ONLY useful for testing and not | ||
719 | * secure as the private keys are part of the public | ||
720 | * GNUnet source code. | ||
721 | * | ||
722 | * This is primarily a helper function used internally | ||
723 | * by #GNUNET_TESTING_peer_configure. | ||
724 | * | ||
725 | * @param system the testing system handle | ||
726 | * @param key_number desired pre-created hostkey to obtain | ||
727 | * @param id set to the peer's identity (hash of the public | ||
728 | * key; if NULL, NULL is returned immediately | ||
729 | * @return NULL on error (not enough keys) | ||
730 | */ | ||
731 | struct GNUNET_CRYPTO_EddsaPrivateKey * | ||
732 | GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system, | ||
733 | uint32_t key_number, | ||
734 | struct GNUNET_PeerIdentity *id) | ||
735 | { | ||
736 | struct GNUNET_CRYPTO_EddsaPrivateKey *private_key; | ||
737 | |||
738 | if ((NULL == id) || (NULL == system->hostkeys_data)) | ||
739 | return NULL; | ||
740 | if (key_number >= system->total_hostkeys) | ||
741 | { | ||
742 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
743 | _ ("Key number %u does not exist\n"), | ||
744 | key_number); | ||
745 | return NULL; | ||
746 | } | ||
747 | private_key = GNUNET_new (struct GNUNET_CRYPTO_EddsaPrivateKey); | ||
748 | GNUNET_memcpy (private_key, | ||
749 | system->hostkeys_data | ||
750 | + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE), | ||
751 | GNUNET_TESTING_HOSTKEYFILESIZE); | ||
752 | GNUNET_CRYPTO_eddsa_key_get_public (private_key, &id->public_key); | ||
753 | return private_key; | ||
754 | } | ||
755 | |||
756 | |||
757 | /** | ||
758 | * Structure for holding data to build new configurations from a configuration | ||
759 | * template | ||
760 | */ | ||
761 | struct UpdateContext | ||
762 | { | ||
763 | /** | ||
764 | * The system for which we are building configurations | ||
765 | */ | ||
766 | struct GNUNET_TESTING_System *system; | ||
767 | |||
768 | /** | ||
769 | * The configuration we are building | ||
770 | */ | ||
771 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
772 | |||
773 | /** | ||
774 | * The customized service home path for this peer | ||
775 | */ | ||
776 | char *gnunet_home; | ||
777 | |||
778 | /** | ||
779 | * Array of ports currently allocated to this peer. These ports will be | ||
780 | * released upon peer destroy and can be used by other peers which are | ||
781 | * configured after. | ||
782 | */ | ||
783 | uint16_t *ports; | ||
784 | |||
785 | /** | ||
786 | * The number of ports in the above array | ||
787 | */ | ||
788 | unsigned int nports; | ||
789 | |||
790 | /** | ||
791 | * build status - to signal error while building a configuration | ||
792 | */ | ||
793 | int status; | ||
794 | }; | ||
795 | |||
796 | |||
797 | /** | ||
798 | * Function to iterate over options. Copies | ||
799 | * the options to the target configuration, | ||
800 | * updating PORT values as needed. | ||
801 | * | ||
802 | * @param cls the UpdateContext | ||
803 | * @param section name of the section | ||
804 | * @param option name of the option | ||
805 | * @param value value of the option | ||
806 | */ | ||
807 | static void | ||
808 | update_config (void *cls, | ||
809 | const char *section, | ||
810 | const char *option, | ||
811 | const char *value) | ||
812 | { | ||
813 | struct UpdateContext *uc = cls; | ||
814 | unsigned int ival; | ||
815 | char cval[12]; | ||
816 | char uval[PATH_MAX]; | ||
817 | char *single_variable; | ||
818 | char *per_host_variable; | ||
819 | unsigned long long num_per_host; | ||
820 | uint16_t new_port; | ||
821 | |||
822 | if (GNUNET_OK != uc->status) | ||
823 | return; | ||
824 | if (! ((0 == strcmp (option, "PORT")) || (0 == strcmp (option, "UNIXPATH")) || | ||
825 | (0 == strcmp (option, "HOSTNAME")))) | ||
826 | return; | ||
827 | GNUNET_asprintf (&single_variable, "single_%s_per_host", section); | ||
828 | GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section); | ||
829 | if ((0 == strcmp (option, "PORT")) && (1 == sscanf (value, "%u", &ival))) | ||
830 | { | ||
831 | if ((ival != 0) && | ||
832 | (GNUNET_YES != GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, | ||
833 | "testing", | ||
834 | single_variable))) | ||
835 | { | ||
836 | new_port = GNUNET_TESTING_reserve_port (uc->system); | ||
837 | if (0 == new_port) | ||
838 | { | ||
839 | uc->status = GNUNET_SYSERR; | ||
840 | GNUNET_free (single_variable); | ||
841 | GNUNET_free (per_host_variable); | ||
842 | return; | ||
843 | } | ||
844 | GNUNET_snprintf (cval, sizeof(cval), "%u", new_port); | ||
845 | value = cval; | ||
846 | GNUNET_array_append (uc->ports, uc->nports, new_port); | ||
847 | } | ||
848 | else if ((ival != 0) && | ||
849 | (GNUNET_YES == | ||
850 | GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, | ||
851 | "testing", | ||
852 | single_variable)) && | ||
853 | GNUNET_CONFIGURATION_get_value_number (uc->cfg, | ||
854 | "testing", | ||
855 | per_host_variable, | ||
856 | &num_per_host)) | ||
857 | { | ||
858 | /* GNUNET_snprintf (cval, sizeof (cval), "%u", */ | ||
859 | /* ival + ctx->fdnum % num_per_host); */ | ||
860 | /* value = cval; */ | ||
861 | GNUNET_break (0); /* FIXME */ | ||
862 | } | ||
863 | } | ||
864 | if (0 == strcmp (option, "UNIXPATH")) | ||
865 | { | ||
866 | if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, | ||
867 | "testing", | ||
868 | single_variable)) | ||
869 | { | ||
870 | GNUNET_snprintf (uval, | ||
871 | sizeof(uval), | ||
872 | "%s/%s.sock", | ||
873 | uc->gnunet_home, | ||
874 | section); | ||
875 | value = uval; | ||
876 | } | ||
877 | else if ((GNUNET_YES == | ||
878 | GNUNET_CONFIGURATION_get_value_number (uc->cfg, | ||
879 | "testing", | ||
880 | per_host_variable, | ||
881 | &num_per_host)) && | ||
882 | (num_per_host > 0)) | ||
883 | { | ||
884 | GNUNET_break (0); /* FIXME */ | ||
885 | } | ||
886 | } | ||
887 | if (0 == strcmp (option, "HOSTNAME")) | ||
888 | { | ||
889 | value = (NULL == uc->system->hostname) ? "localhost" : uc->system->hostname; | ||
890 | } | ||
891 | GNUNET_free (single_variable); | ||
892 | GNUNET_free (per_host_variable); | ||
893 | GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value); | ||
894 | } | ||
895 | |||
896 | |||
897 | /** | ||
898 | * Section iterator to set ACCEPT_FROM/ACCEPT_FROM6 to include the address of | ||
899 | * 'trusted_hosts' in all sections | ||
900 | * | ||
901 | * @param cls the UpdateContext | ||
902 | * @param section name of the section | ||
903 | */ | ||
904 | static void | ||
905 | update_config_sections (void *cls, const char *section) | ||
906 | { | ||
907 | struct UpdateContext *uc = cls; | ||
908 | char **ikeys; | ||
909 | char *val; | ||
910 | char *ptr; | ||
911 | char *orig_allowed_hosts; | ||
912 | char *allowed_hosts; | ||
913 | char *ACCEPT_FROM_key; | ||
914 | uint16_t ikeys_cnt; | ||
915 | uint16_t key; | ||
916 | |||
917 | ikeys_cnt = 0; | ||
918 | val = NULL; | ||
919 | /* Ignore certain options from sections. See | ||
920 | https://gnunet.org/bugs/view.php?id=2476 */ | ||
921 | if (GNUNET_YES == | ||
922 | GNUNET_CONFIGURATION_have_value (uc->cfg, section, "TESTING_IGNORE_KEYS")) | ||
923 | { | ||
924 | GNUNET_assert (GNUNET_YES == | ||
925 | GNUNET_CONFIGURATION_get_value_string (uc->cfg, | ||
926 | section, | ||
927 | "TESTING_IGNORE_KEYS", | ||
928 | &val)); | ||
929 | ptr = val; | ||
930 | for (ikeys_cnt = 0; NULL != (ptr = strstr (ptr, ";")); ikeys_cnt++) | ||
931 | ptr++; | ||
932 | if (0 == ikeys_cnt) | ||
933 | GNUNET_break (0); | ||
934 | else | ||
935 | { | ||
936 | ikeys = GNUNET_malloc ((sizeof(char *)) * ikeys_cnt); | ||
937 | ptr = val; | ||
938 | for (key = 0; key < ikeys_cnt; key++) | ||
939 | { | ||
940 | ikeys[key] = ptr; | ||
941 | ptr = strstr (ptr, ";"); | ||
942 | GNUNET_assert (NULL != ptr); /* worked just before... */ | ||
943 | *ptr = '\0'; | ||
944 | ptr++; | ||
945 | } | ||
946 | } | ||
947 | } | ||
948 | if (0 != ikeys_cnt) | ||
949 | { | ||
950 | for (key = 0; key < ikeys_cnt; key++) | ||
951 | { | ||
952 | if (NULL != strstr (ikeys[key], "ADVERTISED_PORT")) | ||
953 | break; | ||
954 | } | ||
955 | if ((key == ikeys_cnt) && | ||
956 | (GNUNET_YES == | ||
957 | GNUNET_CONFIGURATION_have_value (uc->cfg, section, "ADVERTISED_PORT"))) | ||
958 | { | ||
959 | if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (uc->cfg, | ||
960 | section, | ||
961 | "PORT", | ||
962 | &ptr)) | ||
963 | { | ||
964 | GNUNET_CONFIGURATION_set_value_string (uc->cfg, | ||
965 | section, | ||
966 | "ADVERTISED_PORT", | ||
967 | ptr); | ||
968 | GNUNET_free (ptr); | ||
969 | } | ||
970 | } | ||
971 | for (key = 0; key < ikeys_cnt; key++) | ||
972 | { | ||
973 | if (NULL != strstr (ikeys[key], "ACCEPT_FROM")) | ||
974 | { | ||
975 | GNUNET_free (ikeys); | ||
976 | GNUNET_free (val); | ||
977 | return; | ||
978 | } | ||
979 | } | ||
980 | GNUNET_free (ikeys); | ||
981 | } | ||
982 | GNUNET_free (val); | ||
983 | ACCEPT_FROM_key = "ACCEPT_FROM"; | ||
984 | if ((NULL != uc->system->trusted_ip) && | ||
985 | (NULL != strstr (uc->system->trusted_ip, ":"))) /* IPv6 in use */ | ||
986 | ACCEPT_FROM_key = "ACCEPT_FROM6"; | ||
987 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (uc->cfg, | ||
988 | section, | ||
989 | ACCEPT_FROM_key, | ||
990 | &orig_allowed_hosts)) | ||
991 | { | ||
992 | orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;"); | ||
993 | } | ||
994 | if (NULL == uc->system->trusted_ip) | ||
995 | allowed_hosts = GNUNET_strdup (orig_allowed_hosts); | ||
996 | else | ||
997 | GNUNET_asprintf (&allowed_hosts, | ||
998 | "%s%s;", | ||
999 | orig_allowed_hosts, | ||
1000 | uc->system->trusted_ip); | ||
1001 | GNUNET_free (orig_allowed_hosts); | ||
1002 | GNUNET_CONFIGURATION_set_value_string (uc->cfg, | ||
1003 | section, | ||
1004 | ACCEPT_FROM_key, | ||
1005 | allowed_hosts); | ||
1006 | GNUNET_free (allowed_hosts); | ||
1007 | } | ||
1008 | |||
1009 | |||
1010 | static struct SharedServiceInstance * | ||
1011 | associate_shared_service (struct GNUNET_TESTING_System *system, | ||
1012 | struct SharedService *ss, | ||
1013 | struct GNUNET_CONFIGURATION_Handle *cfg) | ||
1014 | { | ||
1015 | struct SharedServiceInstance *i; | ||
1016 | struct GNUNET_CONFIGURATION_Handle *temp; | ||
1017 | char *gnunet_home; | ||
1018 | uint32_t port; | ||
1019 | |||
1020 | ss->n_peers++; | ||
1021 | if (((0 == ss->share) && (NULL == ss->instances)) || | ||
1022 | ((0 != ss->share) && | ||
1023 | (ss->n_instances < ((ss->n_peers + ss->share - 1) / ss->share)))) | ||
1024 | { | ||
1025 | i = GNUNET_new (struct SharedServiceInstance); | ||
1026 | i->ss = ss; | ||
1027 | (void) GNUNET_asprintf (&gnunet_home, | ||
1028 | "%s/shared/%s/%u", | ||
1029 | system->tmppath, | ||
1030 | ss->sname, | ||
1031 | ss->n_instances); | ||
1032 | (void) GNUNET_asprintf (&i->unix_sock, "%s/sock", gnunet_home); | ||
1033 | port = GNUNET_TESTING_reserve_port (system); | ||
1034 | if (0 == port) | ||
1035 | { | ||
1036 | GNUNET_free (gnunet_home); | ||
1037 | cleanup_shared_service_instance (i); | ||
1038 | return NULL; | ||
1039 | } | ||
1040 | GNUNET_array_append (ss->instances, ss->n_instances, i); | ||
1041 | temp = GNUNET_CONFIGURATION_dup (ss->cfg); | ||
1042 | (void) GNUNET_asprintf (&i->port_str, "%u", port); | ||
1043 | (void) GNUNET_asprintf (&i->cfg_fn, "%s/config", gnunet_home); | ||
1044 | GNUNET_CONFIGURATION_set_value_string (temp, | ||
1045 | "PATHS", | ||
1046 | "GNUNET_HOME", | ||
1047 | gnunet_home); | ||
1048 | GNUNET_free (gnunet_home); | ||
1049 | GNUNET_CONFIGURATION_set_value_string (temp, | ||
1050 | ss->sname, | ||
1051 | "UNIXPATH", | ||
1052 | i->unix_sock); | ||
1053 | GNUNET_CONFIGURATION_set_value_string (temp, | ||
1054 | ss->sname, | ||
1055 | "PORT", | ||
1056 | i->port_str); | ||
1057 | if (GNUNET_SYSERR == GNUNET_CONFIGURATION_write (temp, i->cfg_fn)) | ||
1058 | { | ||
1059 | GNUNET_CONFIGURATION_destroy (temp); | ||
1060 | cleanup_shared_service_instance (i); | ||
1061 | return NULL; | ||
1062 | } | ||
1063 | GNUNET_CONFIGURATION_destroy (temp); | ||
1064 | } | ||
1065 | else | ||
1066 | { | ||
1067 | GNUNET_assert (NULL != ss->instances); | ||
1068 | GNUNET_assert (0 < ss->n_instances); | ||
1069 | i = ss->instances[ss->n_instances - 1]; | ||
1070 | } | ||
1071 | GNUNET_CONFIGURATION_iterate_section_values (ss->cfg, | ||
1072 | ss->sname, | ||
1073 | &cfg_copy_iterator, | ||
1074 | cfg); | ||
1075 | GNUNET_CONFIGURATION_set_value_string (cfg, | ||
1076 | ss->sname, | ||
1077 | "UNIXPATH", | ||
1078 | i->unix_sock); | ||
1079 | GNUNET_CONFIGURATION_set_value_string (cfg, ss->sname, "PORT", i->port_str); | ||
1080 | return i; | ||
1081 | } | ||
1082 | |||
1083 | |||
1084 | /** | ||
1085 | * Create a new configuration using the given configuration as a template; | ||
1086 | * ports and paths will be modified to select available ports on the local | ||
1087 | * system. The default configuration will be available in PATHS section under | ||
1088 | * the option DEFAULTCONFIG after the call. GNUNET_HOME is also set in PATHS | ||
1089 | * section to the temporary directory specific to this configuration. If we run | ||
1090 | * out of "*port" numbers, return #GNUNET_SYSERR. | ||
1091 | * | ||
1092 | * This is primarily a helper function used internally | ||
1093 | * by 'GNUNET_TESTING_peer_configure'. | ||
1094 | * | ||
1095 | * @param system system to use to coordinate resource usage | ||
1096 | * @param cfg template configuration to update | ||
1097 | * @param ports array with port numbers used in the created configuration. | ||
1098 | * Will be updated upon successful return. Can be NULL | ||
1099 | * @param nports the size of the `ports' array. Will be updated. | ||
1100 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - the configuration will | ||
1101 | * be incomplete and should not be used there upon | ||
1102 | */ | ||
1103 | static int | ||
1104 | GNUNET_TESTING_configuration_create_ (struct GNUNET_TESTING_System *system, | ||
1105 | struct GNUNET_CONFIGURATION_Handle *cfg, | ||
1106 | uint16_t **ports, | ||
1107 | unsigned int *nports) | ||
1108 | { | ||
1109 | struct UpdateContext uc; | ||
1110 | char *default_config; | ||
1111 | |||
1112 | uc.system = system; | ||
1113 | uc.cfg = cfg; | ||
1114 | uc.status = GNUNET_OK; | ||
1115 | uc.ports = NULL; | ||
1116 | uc.nports = 0; | ||
1117 | GNUNET_asprintf (&uc.gnunet_home, | ||
1118 | "%s/%u", | ||
1119 | system->tmppath, | ||
1120 | system->path_counter++); | ||
1121 | GNUNET_asprintf (&default_config, "%s/config", uc.gnunet_home); | ||
1122 | GNUNET_CONFIGURATION_set_value_string (cfg, | ||
1123 | "PATHS", | ||
1124 | "DEFAULTCONFIG", | ||
1125 | default_config); | ||
1126 | GNUNET_CONFIGURATION_set_value_string (cfg, "arm", "CONFIG", default_config); | ||
1127 | GNUNET_free (default_config); | ||
1128 | GNUNET_CONFIGURATION_set_value_string (cfg, | ||
1129 | "PATHS", | ||
1130 | "GNUNET_HOME", | ||
1131 | uc.gnunet_home); | ||
1132 | /* make PORTs and UNIXPATHs unique */ | ||
1133 | GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc); | ||
1134 | /* allow connections to services from system trusted_ip host */ | ||
1135 | GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc); | ||
1136 | /* enable loopback-based connections between peers */ | ||
1137 | GNUNET_CONFIGURATION_set_value_string (cfg, "nat", "USE_LOCALADDR", "YES"); | ||
1138 | GNUNET_free (uc.gnunet_home); | ||
1139 | if ((NULL != ports) && (NULL != nports)) | ||
1140 | { | ||
1141 | *ports = uc.ports; | ||
1142 | *nports = uc.nports; | ||
1143 | } | ||
1144 | else | ||
1145 | GNUNET_free (uc.ports); | ||
1146 | return uc.status; | ||
1147 | } | ||
1148 | |||
1149 | |||
1150 | /** | ||
1151 | * Create a new configuration using the given configuration as a template; | ||
1152 | * ports and paths will be modified to select available ports on the local | ||
1153 | * system. The default configuration will be available in PATHS section under | ||
1154 | * the option DEFAULTCONFIG after the call. GNUNET_HOME is also set in PATHS | ||
1155 | * section to the temporary directory specific to this configuration. If we run | ||
1156 | * out of "*port" numbers, return #GNUNET_SYSERR. | ||
1157 | * | ||
1158 | * This is primarily a helper function used internally | ||
1159 | * by #GNUNET_TESTING_peer_configure(). | ||
1160 | * | ||
1161 | * @param system system to use to coordinate resource usage | ||
1162 | * @param cfg template configuration to update | ||
1163 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - the configuration will | ||
1164 | * be incomplete and should not be used there upon | ||
1165 | */ | ||
1166 | int | ||
1167 | GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system, | ||
1168 | struct GNUNET_CONFIGURATION_Handle *cfg) | ||
1169 | { | ||
1170 | return GNUNET_TESTING_configuration_create_ (system, cfg, NULL, NULL); | ||
1171 | } | ||
1172 | |||
1173 | |||
1174 | /** | ||
1175 | * Configure a GNUnet peer. GNUnet must be installed on the local | ||
1176 | * system and available in the PATH. | ||
1177 | * | ||
1178 | * @param system system to use to coordinate resource usage | ||
1179 | * @param cfg configuration to use; will be UPDATED (to reflect needed | ||
1180 | * changes in port numbers and paths) | ||
1181 | * @param key_number number of the hostkey to use for the peer | ||
1182 | * @param id identifier for the daemon, will be set, can be NULL | ||
1183 | * @param emsg set to freshly allocated error message (set to NULL on success), | ||
1184 | * can be NULL | ||
1185 | * @return handle to the peer, NULL on error | ||
1186 | */ | ||
1187 | struct GNUNET_TESTING_Peer * | ||
1188 | GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system, | ||
1189 | struct GNUNET_CONFIGURATION_Handle *cfg, | ||
1190 | uint32_t key_number, | ||
1191 | struct GNUNET_PeerIdentity *id, | ||
1192 | char **emsg) | ||
1193 | { | ||
1194 | struct GNUNET_TESTING_Peer *peer; | ||
1195 | struct GNUNET_DISK_FileHandle *fd; | ||
1196 | char *hostkey_filename; | ||
1197 | char *config_filename; | ||
1198 | char *libexec_binary; | ||
1199 | char *emsg_; | ||
1200 | struct GNUNET_CRYPTO_EddsaPrivateKey *pk; | ||
1201 | uint16_t *ports; | ||
1202 | struct SharedService *ss; | ||
1203 | struct SharedServiceInstance **ss_instances; | ||
1204 | unsigned int cnt; | ||
1205 | unsigned int nports; | ||
1206 | |||
1207 | ports = NULL; | ||
1208 | nports = 0; | ||
1209 | ss_instances = NULL; | ||
1210 | if (NULL != emsg) | ||
1211 | *emsg = NULL; | ||
1212 | if (key_number >= system->total_hostkeys) | ||
1213 | { | ||
1214 | GNUNET_asprintf ( | ||
1215 | &emsg_, | ||
1216 | _ ( | ||
1217 | "You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"), | ||
1218 | (unsigned int) system->total_hostkeys); | ||
1219 | goto err_ret; | ||
1220 | } | ||
1221 | pk = NULL; | ||
1222 | if ((NULL != id) && | ||
1223 | (NULL == (pk = GNUNET_TESTING_hostkey_get (system, key_number, id)))) | ||
1224 | { | ||
1225 | GNUNET_asprintf (&emsg_, | ||
1226 | _ ("Failed to initialize hostkey for peer %u\n"), | ||
1227 | (unsigned int) key_number); | ||
1228 | goto err_ret; | ||
1229 | } | ||
1230 | if (NULL != pk) | ||
1231 | GNUNET_free (pk); | ||
1232 | if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (cfg, "PEER", "PRIVATE_KEY")) | ||
1233 | { | ||
1234 | GNUNET_asprintf ( | ||
1235 | &emsg_, | ||
1236 | _ ("PRIVATE_KEY option in PEER section missing in configuration\n")); | ||
1237 | goto err_ret; | ||
1238 | } | ||
1239 | /* Remove sections for shared services */ | ||
1240 | for (cnt = 0; cnt < system->n_shared_services; cnt++) | ||
1241 | { | ||
1242 | ss = &system->shared_services[cnt]; | ||
1243 | GNUNET_CONFIGURATION_remove_section (cfg, ss->sname); | ||
1244 | } | ||
1245 | if (GNUNET_OK != | ||
1246 | GNUNET_TESTING_configuration_create_ (system, cfg, &ports, &nports)) | ||
1247 | { | ||
1248 | GNUNET_asprintf (&emsg_, | ||
1249 | _ ("Failed to create configuration for peer " | ||
1250 | "(not enough free ports?)\n")); | ||
1251 | goto err_ret; | ||
1252 | } | ||
1253 | GNUNET_assert (GNUNET_OK == | ||
1254 | GNUNET_CONFIGURATION_get_value_filename (cfg, | ||
1255 | "PEER", | ||
1256 | "PRIVATE_KEY", | ||
1257 | &hostkey_filename)); | ||
1258 | fd = GNUNET_DISK_file_open (hostkey_filename, | ||
1259 | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE, | ||
1260 | GNUNET_DISK_PERM_USER_READ | ||
1261 | | GNUNET_DISK_PERM_USER_WRITE); | ||
1262 | if (NULL == fd) | ||
1263 | { | ||
1264 | GNUNET_asprintf (&emsg_, | ||
1265 | _ ("Cannot open hostkey file `%s': %s\n"), | ||
1266 | hostkey_filename, | ||
1267 | strerror (errno)); | ||
1268 | GNUNET_free (hostkey_filename); | ||
1269 | goto err_ret; | ||
1270 | } | ||
1271 | GNUNET_free (hostkey_filename); | ||
1272 | if (GNUNET_TESTING_HOSTKEYFILESIZE != | ||
1273 | GNUNET_DISK_file_write (fd, | ||
1274 | system->hostkeys_data | ||
1275 | + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE), | ||
1276 | GNUNET_TESTING_HOSTKEYFILESIZE)) | ||
1277 | { | ||
1278 | GNUNET_asprintf (&emsg_, | ||
1279 | _ ("Failed to write hostkey file for peer %u: %s\n"), | ||
1280 | (unsigned int) key_number, | ||
1281 | strerror (errno)); | ||
1282 | GNUNET_DISK_file_close (fd); | ||
1283 | goto err_ret; | ||
1284 | } | ||
1285 | GNUNET_DISK_file_close (fd); | ||
1286 | ss_instances = GNUNET_new_array (system->n_shared_services, | ||
1287 | struct SharedServiceInstance*); | ||
1288 | for (cnt = 0; cnt < system->n_shared_services; cnt++) | ||
1289 | { | ||
1290 | ss = &system->shared_services[cnt]; | ||
1291 | ss_instances[cnt] = associate_shared_service (system, ss, cfg); | ||
1292 | if (NULL == ss_instances[cnt]) | ||
1293 | { | ||
1294 | emsg_ = GNUNET_strdup ("FIXME"); | ||
1295 | goto err_ret; | ||
1296 | } | ||
1297 | } | ||
1298 | GNUNET_assert (GNUNET_OK == | ||
1299 | GNUNET_CONFIGURATION_get_value_filename (cfg, | ||
1300 | "PATHS", | ||
1301 | "DEFAULTCONFIG", | ||
1302 | &config_filename)); | ||
1303 | if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename)) | ||
1304 | { | ||
1305 | GNUNET_asprintf (&emsg_, | ||
1306 | _ ( | ||
1307 | "Failed to write configuration file `%s' for peer %u: %s\n"), | ||
1308 | config_filename, | ||
1309 | (unsigned int) key_number, | ||
1310 | strerror (errno)); | ||
1311 | GNUNET_free (config_filename); | ||
1312 | goto err_ret; | ||
1313 | } | ||
1314 | peer = GNUNET_new (struct GNUNET_TESTING_Peer); | ||
1315 | peer->ss_instances = ss_instances; | ||
1316 | peer->cfgfile = config_filename; /* Free in peer_destroy */ | ||
1317 | peer->cfg = GNUNET_CONFIGURATION_dup (cfg); | ||
1318 | libexec_binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm"); | ||
1319 | if (GNUNET_SYSERR == | ||
1320 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
1321 | "arm", | ||
1322 | "PREFIX", | ||
1323 | &peer->main_binary)) | ||
1324 | { | ||
1325 | /* No prefix */ | ||
1326 | GNUNET_asprintf (&peer->main_binary, "%s", libexec_binary); | ||
1327 | peer->args = GNUNET_strdup (""); | ||
1328 | } | ||
1329 | else | ||
1330 | { | ||
1331 | peer->args = GNUNET_strdup (libexec_binary); | ||
1332 | } | ||
1333 | peer->system = system; | ||
1334 | peer->key_number = key_number; | ||
1335 | GNUNET_free (libexec_binary); | ||
1336 | peer->ports = ports; /* Free in peer_destroy */ | ||
1337 | peer->nports = nports; | ||
1338 | return peer; | ||
1339 | |||
1340 | err_ret: | ||
1341 | GNUNET_free (ss_instances); | ||
1342 | GNUNET_free (ports); | ||
1343 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_); | ||
1344 | if (NULL != emsg) | ||
1345 | *emsg = emsg_; | ||
1346 | else | ||
1347 | GNUNET_free (emsg_); | ||
1348 | return NULL; | ||
1349 | } | ||
1350 | |||
1351 | |||
1352 | /** | ||
1353 | * Obtain the peer identity from a peer handle. | ||
1354 | * | ||
1355 | * @param peer peer handle for which we want the peer's identity | ||
1356 | * @param id identifier for the daemon, will be set | ||
1357 | */ | ||
1358 | void | ||
1359 | GNUNET_TESTING_peer_get_identity (struct GNUNET_TESTING_Peer *peer, | ||
1360 | struct GNUNET_PeerIdentity *id) | ||
1361 | { | ||
1362 | if (NULL != peer->id) | ||
1363 | { | ||
1364 | GNUNET_memcpy (id, peer->id, sizeof(struct GNUNET_PeerIdentity)); | ||
1365 | return; | ||
1366 | } | ||
1367 | peer->id = GNUNET_new (struct GNUNET_PeerIdentity); | ||
1368 | GNUNET_free_nz ( | ||
1369 | GNUNET_TESTING_hostkey_get (peer->system, peer->key_number, peer->id)); | ||
1370 | GNUNET_memcpy (id, peer->id, sizeof(struct GNUNET_PeerIdentity)); | ||
1371 | } | ||
1372 | |||
1373 | |||
1374 | /** | ||
1375 | * Start the peer. | ||
1376 | * | ||
1377 | * @param peer peer to start | ||
1378 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (i.e. peer already running) | ||
1379 | */ | ||
1380 | int | ||
1381 | GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer) | ||
1382 | { | ||
1383 | struct SharedServiceInstance *i; | ||
1384 | unsigned int cnt; | ||
1385 | |||
1386 | if (NULL != peer->main_process) | ||
1387 | { | ||
1388 | GNUNET_break (0); | ||
1389 | return GNUNET_SYSERR; | ||
1390 | } | ||
1391 | GNUNET_assert (NULL != peer->cfgfile); | ||
1392 | for (cnt = 0; cnt < peer->system->n_shared_services; cnt++) | ||
1393 | { | ||
1394 | i = peer->ss_instances[cnt]; | ||
1395 | if ((0 == i->n_refs) && | ||
1396 | (GNUNET_SYSERR == start_shared_service_instance (i))) | ||
1397 | return GNUNET_SYSERR; | ||
1398 | i->n_refs++; | ||
1399 | } | ||
1400 | peer->main_binary = | ||
1401 | GNUNET_CONFIGURATION_expand_dollar (peer->cfg, peer->main_binary); | ||
1402 | peer->main_process = | ||
1403 | GNUNET_OS_start_process_s (GNUNET_OS_INHERIT_STD_OUT_AND_ERR, | ||
1404 | NULL, | ||
1405 | peer->main_binary, | ||
1406 | peer->args, | ||
1407 | "-c", | ||
1408 | peer->cfgfile, | ||
1409 | NULL); | ||
1410 | if (NULL == peer->main_process) | ||
1411 | { | ||
1412 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1413 | _ ("Failed to start `%s': %s\n"), | ||
1414 | peer->main_binary, | ||
1415 | strerror (errno)); | ||
1416 | return GNUNET_SYSERR; | ||
1417 | } | ||
1418 | return GNUNET_OK; | ||
1419 | } | ||
1420 | |||
1421 | |||
1422 | /** | ||
1423 | * Sends SIGTERM to the peer's main process | ||
1424 | * | ||
1425 | * @param peer the handle to the peer | ||
1426 | * @return #GNUNET_OK if successful; #GNUNET_SYSERR if the main process is NULL | ||
1427 | * or upon any error while sending SIGTERM | ||
1428 | */ | ||
1429 | int | ||
1430 | GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer) | ||
1431 | { | ||
1432 | struct SharedServiceInstance *i; | ||
1433 | unsigned int cnt; | ||
1434 | |||
1435 | if (NULL == peer->main_process) | ||
1436 | { | ||
1437 | GNUNET_break (0); | ||
1438 | return GNUNET_SYSERR; | ||
1439 | } | ||
1440 | if (0 != GNUNET_OS_process_kill (peer->main_process, GNUNET_TERM_SIG)) | ||
1441 | return GNUNET_SYSERR; | ||
1442 | for (cnt = 0; cnt < peer->system->n_shared_services; cnt++) | ||
1443 | { | ||
1444 | i = peer->ss_instances[cnt]; | ||
1445 | GNUNET_assert (0 != i->n_refs); | ||
1446 | i->n_refs--; | ||
1447 | if (0 == i->n_refs) | ||
1448 | stop_shared_service_instance (i); | ||
1449 | } | ||
1450 | return GNUNET_OK; | ||
1451 | } | ||
1452 | |||
1453 | |||
1454 | /** | ||
1455 | * Waits for a peer to terminate. The peer's main process will also be destroyed. | ||
1456 | * | ||
1457 | * @param peer the handle to the peer | ||
1458 | * @return #GNUNET_OK if successful; #GNUNET_SYSERR if the main process is NULL | ||
1459 | * or upon any error while waiting | ||
1460 | */ | ||
1461 | int | ||
1462 | GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer) | ||
1463 | { | ||
1464 | int ret; | ||
1465 | |||
1466 | if (NULL == peer->main_process) | ||
1467 | { | ||
1468 | GNUNET_break (0); | ||
1469 | return GNUNET_SYSERR; | ||
1470 | } | ||
1471 | ret = GNUNET_OS_process_wait (peer->main_process); | ||
1472 | GNUNET_OS_process_destroy (peer->main_process); | ||
1473 | peer->main_process = NULL; | ||
1474 | return ret; | ||
1475 | } | ||
1476 | |||
1477 | |||
1478 | /** | ||
1479 | * Stop the peer. | ||
1480 | * | ||
1481 | * @param peer peer to stop | ||
1482 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error | ||
1483 | */ | ||
1484 | int | ||
1485 | GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer) | ||
1486 | { | ||
1487 | if (GNUNET_SYSERR == GNUNET_TESTING_peer_kill (peer)) | ||
1488 | return GNUNET_SYSERR; | ||
1489 | if (GNUNET_SYSERR == GNUNET_TESTING_peer_wait (peer)) | ||
1490 | return GNUNET_SYSERR; | ||
1491 | return GNUNET_OK; | ||
1492 | } | ||
1493 | |||
1494 | |||
1495 | /** | ||
1496 | * Function called whenever we connect to or disconnect from ARM. | ||
1497 | * | ||
1498 | * @param cls closure | ||
1499 | * @param connected #GNUNET_YES if connected, #GNUNET_NO if disconnected, | ||
1500 | * #GNUNET_SYSERR on error. | ||
1501 | */ | ||
1502 | static void | ||
1503 | disconn_status (void *cls, int connected) | ||
1504 | { | ||
1505 | struct GNUNET_TESTING_Peer *peer = cls; | ||
1506 | |||
1507 | if (GNUNET_SYSERR == connected) | ||
1508 | { | ||
1509 | peer->cb (peer->cb_cls, peer, connected); | ||
1510 | return; | ||
1511 | } | ||
1512 | if (GNUNET_YES == connected) | ||
1513 | { | ||
1514 | GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_kill (peer)); | ||
1515 | return; | ||
1516 | } | ||
1517 | GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_wait (peer)); | ||
1518 | GNUNET_ARM_disconnect (peer->ah); | ||
1519 | peer->ah = NULL; | ||
1520 | peer->cb (peer->cb_cls, peer, GNUNET_YES); | ||
1521 | } | ||
1522 | |||
1523 | |||
1524 | int | ||
1525 | GNUNET_TESTING_peer_stop_async (struct GNUNET_TESTING_Peer *peer, | ||
1526 | GNUNET_TESTING_PeerStopCallback cb, | ||
1527 | void *cb_cls) | ||
1528 | { | ||
1529 | if (NULL == peer->main_process) | ||
1530 | return GNUNET_SYSERR; | ||
1531 | peer->ah = GNUNET_ARM_connect (peer->cfg, &disconn_status, peer); | ||
1532 | if (NULL == peer->ah) | ||
1533 | return GNUNET_SYSERR; | ||
1534 | peer->cb = cb; | ||
1535 | peer->cb_cls = cb_cls; | ||
1536 | return GNUNET_OK; | ||
1537 | } | ||
1538 | |||
1539 | |||
1540 | /** | ||
1541 | * Cancel a previous asynchronous peer stop request. | ||
1542 | * GNUNET_TESTING_peer_stop_async() should have been called before on the given | ||
1543 | * peer. It is an error to call this function if the peer stop callback was | ||
1544 | * already called | ||
1545 | * | ||
1546 | * @param peer the peer on which GNUNET_TESTING_peer_stop_async() was called | ||
1547 | * before. | ||
1548 | */ | ||
1549 | void | ||
1550 | GNUNET_TESTING_peer_stop_async_cancel (struct GNUNET_TESTING_Peer *peer) | ||
1551 | { | ||
1552 | GNUNET_assert (NULL != peer->ah); | ||
1553 | GNUNET_ARM_disconnect (peer->ah); | ||
1554 | peer->ah = NULL; | ||
1555 | } | ||
1556 | |||
1557 | |||
1558 | /** | ||
1559 | * Destroy the peer. Releases resources locked during peer configuration. | ||
1560 | * If the peer is still running, it will be stopped AND a warning will be | ||
1561 | * printed (users of the API should stop the peer explicitly first). | ||
1562 | * | ||
1563 | * @param peer peer to destroy | ||
1564 | */ | ||
1565 | void | ||
1566 | GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer) | ||
1567 | { | ||
1568 | unsigned int cnt; | ||
1569 | |||
1570 | if (NULL != peer->main_process) | ||
1571 | GNUNET_TESTING_peer_stop (peer); | ||
1572 | if (NULL != peer->ah) | ||
1573 | GNUNET_ARM_disconnect (peer->ah); | ||
1574 | GNUNET_free (peer->cfgfile); | ||
1575 | if (NULL != peer->cfg) | ||
1576 | GNUNET_CONFIGURATION_destroy (peer->cfg); | ||
1577 | GNUNET_free (peer->main_binary); | ||
1578 | GNUNET_free (peer->args); | ||
1579 | GNUNET_free (peer->id); | ||
1580 | GNUNET_free (peer->ss_instances); | ||
1581 | if (NULL != peer->ports) | ||
1582 | { | ||
1583 | for (cnt = 0; cnt < peer->nports; cnt++) | ||
1584 | GNUNET_TESTING_release_port (peer->system, peer->ports[cnt]); | ||
1585 | GNUNET_free (peer->ports); | ||
1586 | } | ||
1587 | GNUNET_free (peer); | ||
1588 | } | ||
1589 | |||
1590 | |||
1591 | int | ||
1592 | GNUNET_TESTING_peer_run (const char *testdir, | ||
1593 | const char *cfgfilename, | ||
1594 | GNUNET_TESTING_TestMain tm, | ||
1595 | void *tm_cls) | ||
1596 | { | ||
1597 | return GNUNET_TESTING_service_run (testdir, "arm", cfgfilename, tm, tm_cls); | ||
1598 | } | ||
1599 | |||
1600 | |||
1601 | /** | ||
1602 | * Structure for holding service data | ||
1603 | */ | ||
1604 | struct ServiceContext | ||
1605 | { | ||
1606 | /** | ||
1607 | * The configuration of the peer in which the service is run | ||
1608 | */ | ||
1609 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
1610 | |||
1611 | /** | ||
1612 | * Callback to signal service startup | ||
1613 | */ | ||
1614 | GNUNET_TESTING_TestMain tm; | ||
1615 | |||
1616 | /** | ||
1617 | * The peer in which the service is run. | ||
1618 | */ | ||
1619 | struct GNUNET_TESTING_Peer *peer; | ||
1620 | |||
1621 | /** | ||
1622 | * Closure for the above callback | ||
1623 | */ | ||
1624 | void *tm_cls; | ||
1625 | }; | ||
1626 | |||
1627 | |||
1628 | /** | ||
1629 | * Callback to be called when SCHEDULER has been started | ||
1630 | * | ||
1631 | * @param cls the ServiceContext | ||
1632 | */ | ||
1633 | static void | ||
1634 | service_run_main (void *cls) | ||
1635 | { | ||
1636 | struct ServiceContext *sc = cls; | ||
1637 | |||
1638 | sc->tm (sc->tm_cls, sc->cfg, sc->peer); | ||
1639 | } | ||
1640 | |||
1641 | |||
1642 | int | ||
1643 | GNUNET_TESTING_service_run (const char *testdir, | ||
1644 | const char *service_name, | ||
1645 | const char *cfgfilename, | ||
1646 | GNUNET_TESTING_TestMain tm, | ||
1647 | void *tm_cls) | ||
1648 | { | ||
1649 | struct ServiceContext sc; | ||
1650 | struct GNUNET_TESTING_System *system; | ||
1651 | struct GNUNET_TESTING_Peer *peer; | ||
1652 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
1653 | char *binary; | ||
1654 | char *libexec_binary; | ||
1655 | |||
1656 | GNUNET_log_setup (testdir, "WARNING", NULL); | ||
1657 | system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL, NULL); | ||
1658 | if (NULL == system) | ||
1659 | return 1; | ||
1660 | cfg = GNUNET_CONFIGURATION_create (); | ||
1661 | if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename)) | ||
1662 | { | ||
1663 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1664 | _ ("Failed to load configuration from %s\n"), | ||
1665 | cfgfilename); | ||
1666 | GNUNET_CONFIGURATION_destroy (cfg); | ||
1667 | GNUNET_TESTING_system_destroy (system, GNUNET_YES); | ||
1668 | return 1; | ||
1669 | } | ||
1670 | peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL); | ||
1671 | if (NULL == peer) | ||
1672 | { | ||
1673 | GNUNET_CONFIGURATION_destroy (cfg); | ||
1674 | hostkeys_unload (system); | ||
1675 | GNUNET_TESTING_system_destroy (system, GNUNET_YES); | ||
1676 | return 1; | ||
1677 | } | ||
1678 | GNUNET_free (peer->main_binary); | ||
1679 | GNUNET_free (peer->args); | ||
1680 | GNUNET_asprintf (&binary, "gnunet-service-%s", service_name); | ||
1681 | libexec_binary = GNUNET_OS_get_libexec_binary_path (binary); | ||
1682 | if (GNUNET_SYSERR == | ||
1683 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
1684 | service_name, | ||
1685 | "PREFIX", | ||
1686 | &peer->main_binary)) | ||
1687 | { | ||
1688 | /* No prefix */ | ||
1689 | GNUNET_asprintf (&peer->main_binary, "%s", libexec_binary); | ||
1690 | peer->args = GNUNET_strdup (""); | ||
1691 | } | ||
1692 | else | ||
1693 | peer->args = GNUNET_strdup (libexec_binary); | ||
1694 | |||
1695 | GNUNET_free (libexec_binary); | ||
1696 | GNUNET_free (binary); | ||
1697 | if (GNUNET_OK != GNUNET_TESTING_peer_start (peer)) | ||
1698 | { | ||
1699 | GNUNET_TESTING_peer_destroy (peer); | ||
1700 | GNUNET_CONFIGURATION_destroy (cfg); | ||
1701 | GNUNET_TESTING_system_destroy (system, GNUNET_YES); | ||
1702 | return 1; | ||
1703 | } | ||
1704 | sc.cfg = cfg; | ||
1705 | sc.tm = tm; | ||
1706 | sc.tm_cls = tm_cls; | ||
1707 | sc.peer = peer; | ||
1708 | GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */ | ||
1709 | if ((NULL != peer->main_process) && | ||
1710 | (GNUNET_OK != GNUNET_TESTING_peer_stop (peer))) | ||
1711 | { | ||
1712 | GNUNET_TESTING_peer_destroy (peer); | ||
1713 | GNUNET_CONFIGURATION_destroy (cfg); | ||
1714 | GNUNET_TESTING_system_destroy (system, GNUNET_YES); | ||
1715 | return 1; | ||
1716 | } | ||
1717 | GNUNET_TESTING_peer_destroy (peer); | ||
1718 | GNUNET_CONFIGURATION_destroy (cfg); | ||
1719 | GNUNET_TESTING_system_destroy (system, GNUNET_YES); | ||
1720 | return 0; | ||
1721 | } | ||
1722 | |||
1723 | |||
1724 | /** | ||
1725 | * Every line in the topology configuration starts with a string indicating which | ||
1726 | * kind of information will be configured with this line. Configuration values following | ||
1727 | * this string are seperated by special sequences of characters. An integer value seperated | ||
1728 | * by ':' is returned by this function. | ||
1729 | * | ||
1730 | * @param line The line of configuration. | ||
1731 | * @return An integer value. | ||
1732 | */ | ||
1733 | static unsigned int | ||
1734 | get_first_value (const char *line) | ||
1735 | { | ||
1736 | char *copy; | ||
1737 | size_t slen; | ||
1738 | char *token; | ||
1739 | unsigned int ret; | ||
1740 | char *rest = NULL; | ||
1741 | |||
1742 | slen = strlen (line) + 1; | ||
1743 | copy = GNUNET_malloc (slen); | ||
1744 | memcpy (copy, line, slen); | ||
1745 | token = strtok_r (copy, ":", &rest); | ||
1746 | token = strtok_r (NULL, ":", &rest); | ||
1747 | GNUNET_assert (1 == sscanf (token, "%u", &ret)); | ||
1748 | GNUNET_free (copy); | ||
1749 | return ret; | ||
1750 | } | ||
1751 | |||
1752 | |||
1753 | /** | ||
1754 | * Every line in the topology configuration starts with a string indicating which | ||
1755 | * kind of information will be configured with this line. This string is returned by this function. | ||
1756 | * | ||
1757 | * @param line The line of configuration. | ||
1758 | * @return The leading string of this configuration line. | ||
1759 | */ | ||
1760 | static char * | ||
1761 | get_key (const char *line) | ||
1762 | { | ||
1763 | char *copy; | ||
1764 | size_t slen; | ||
1765 | size_t tlen; | ||
1766 | char *token; | ||
1767 | char *ret; | ||
1768 | char *rest = NULL; | ||
1769 | |||
1770 | slen = strlen (line) + 1; | ||
1771 | copy = GNUNET_malloc (slen); | ||
1772 | memcpy (copy, line, slen); | ||
1773 | token = strtok_r (copy, ":", &rest); | ||
1774 | tlen = strlen (token) + 1; | ||
1775 | ret = GNUNET_malloc (tlen); | ||
1776 | memcpy (ret, token, tlen); | ||
1777 | GNUNET_free (copy); | ||
1778 | return ret; | ||
1779 | } | ||
1780 | |||
1781 | |||
1782 | /** | ||
1783 | * Every line in the topology configuration starts with a string indicating which | ||
1784 | * kind of information will be configured with this line. Configuration values following | ||
1785 | * this string are seperated by special sequences of characters. A string value seperated | ||
1786 | * by ':' is returned by this function. | ||
1787 | * | ||
1788 | * @param line The line of configuration. | ||
1789 | * @return A string value. | ||
1790 | */ | ||
1791 | static char * | ||
1792 | get_first_string_value (const char *line) | ||
1793 | { | ||
1794 | char *copy; | ||
1795 | size_t slen, slen_token; | ||
1796 | char *token; | ||
1797 | char *ret; | ||
1798 | char *rest = NULL; | ||
1799 | |||
1800 | slen = strlen (line) + 1; | ||
1801 | copy = GNUNET_malloc (slen); | ||
1802 | memcpy (copy, line, slen); | ||
1803 | token = strtok_r (copy, ":", &rest); | ||
1804 | token = strtok_r (NULL, ":", &rest); | ||
1805 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1806 | "first token %s\n", | ||
1807 | token); | ||
1808 | slen_token = strlen (token); | ||
1809 | ret = GNUNET_malloc (slen_token + 1); | ||
1810 | memcpy (ret, token, slen_token + 1); | ||
1811 | GNUNET_free (copy); | ||
1812 | return ret; | ||
1813 | } | ||
1814 | |||
1815 | |||
1816 | /** | ||
1817 | * Every line in the topology configuration starts with a string indicating which | ||
1818 | * kind of information will be configured with this line. Configuration values following | ||
1819 | * this string are seperated by special sequences of characters. A second integer value | ||
1820 | * seperated by ':' from a first value is returned by this function. | ||
1821 | * | ||
1822 | * @param line The line of configuration. | ||
1823 | * @return An integer value. | ||
1824 | */ | ||
1825 | static unsigned int | ||
1826 | get_second_value (const char *line) | ||
1827 | { | ||
1828 | char *copy; | ||
1829 | char *token; | ||
1830 | unsigned int ret; | ||
1831 | char *rest = NULL; | ||
1832 | |||
1833 | copy = GNUNET_strdup (line); | ||
1834 | token = strtok_r (copy, ":", &rest); | ||
1835 | token = strtok_r (NULL, ":", &rest); | ||
1836 | token = strtok_r (NULL, ":", &rest); | ||
1837 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1838 | "Format error in configuration line: %s\n", | ||
1839 | line); | ||
1840 | GNUNET_assert (1 == sscanf (token, "%u", &ret)); | ||
1841 | GNUNET_free (copy); | ||
1842 | return ret; | ||
1843 | } | ||
1844 | |||
1845 | |||
1846 | /** | ||
1847 | * Every line in the topology configuration starts with a string indicating which | ||
1848 | * kind of information will be configured with this line. Configuration values following | ||
1849 | * this string are seperated by special sequences of characters. A value might be | ||
1850 | * a key value pair. | ||
1851 | * This function returns the value for a specific key in a configuration line. | ||
1852 | * | ||
1853 | * @param key The key of the key value pair. | ||
1854 | * @return The value of the key value pair. | ||
1855 | */ | ||
1856 | static char * | ||
1857 | get_value (const char *key, const char *line) | ||
1858 | { | ||
1859 | char copy[strlen (line) + 1]; | ||
1860 | size_t slen; | ||
1861 | char *token; | ||
1862 | char *token2; | ||
1863 | char *temp; | ||
1864 | char *rest = NULL; | ||
1865 | |||
1866 | slen = strlen (line) + 1; | ||
1867 | memcpy (copy, line, slen); | ||
1868 | temp = strstr (copy, key); | ||
1869 | if (NULL == temp) | ||
1870 | return NULL; | ||
1871 | token = strtok_r (temp, ":", &rest); | ||
1872 | if (NULL == token) | ||
1873 | return NULL; | ||
1874 | token = strtok_r (NULL, ":", &rest); | ||
1875 | if (NULL == token) | ||
1876 | return NULL; | ||
1877 | token2 = strtok_r (token, "}", &rest); | ||
1878 | if (NULL == token2) | ||
1879 | return NULL; | ||
1880 | return GNUNET_strdup (token2); | ||
1881 | } | ||
1882 | |||
1883 | |||
1884 | /** | ||
1885 | * Every line in the topology configuration starts with a string indicating which | ||
1886 | * kind of information will be configured with this line. Configuration values following | ||
1887 | * this string are seperated by special sequences of characters. A value might be | ||
1888 | * a key value pair. A special key is the 'connect' key which can appear more than once. | ||
1889 | * The value is the information about a connection via some protocol to some other node. | ||
1890 | * This function returns the struct GNUNET_TESTING_NodeConnection which holds the information | ||
1891 | * of the connect value. | ||
1892 | * | ||
1893 | * @param value The value of the connect key value pair. | ||
1894 | * @return The struct GNUNET_TESTING_NodeConnection. | ||
1895 | */ | ||
1896 | static struct GNUNET_TESTING_NodeConnection * | ||
1897 | get_connect_value (const char *line, | ||
1898 | struct GNUNET_TESTING_NetjailNode *node) | ||
1899 | { | ||
1900 | struct GNUNET_TESTING_NodeConnection *node_connection; | ||
1901 | char *copy; | ||
1902 | char *token; | ||
1903 | char *token2; | ||
1904 | unsigned int node_n; | ||
1905 | unsigned int namespace_n; | ||
1906 | char *rest = NULL; | ||
1907 | char *rest2 = NULL; | ||
1908 | struct GNUNET_TESTING_AddressPrefix *prefix; | ||
1909 | unsigned int sscanf_ret; | ||
1910 | |||
1911 | node_connection = GNUNET_new (struct GNUNET_TESTING_NodeConnection); | ||
1912 | node_connection->node = node; | ||
1913 | |||
1914 | copy = GNUNET_strdup (line); | ||
1915 | token = strtok_r (copy, ":", &rest); | ||
1916 | if (0 == strcmp ("{K", token)) | ||
1917 | { | ||
1918 | node_connection->node_type = GNUNET_TESTING_GLOBAL_NODE; | ||
1919 | token = strtok_r (NULL, ":", &rest); | ||
1920 | GNUNET_assert (1 == sscanf (token, "%u", &node_n)); | ||
1921 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1922 | "node_n %u\n", | ||
1923 | node_n); | ||
1924 | node_connection->node_n = node_n; | ||
1925 | node_connection->namespace_n = 0; | ||
1926 | } | ||
1927 | else if (0 == strcmp ("{P", token)) | ||
1928 | { | ||
1929 | node_connection->node_type = GNUNET_TESTING_SUBNET_NODE; | ||
1930 | token = strtok_r (NULL, ":", &rest); | ||
1931 | errno = 0; | ||
1932 | sscanf_ret = sscanf (token, "%u", &namespace_n); | ||
1933 | if (errno != 0) | ||
1934 | { | ||
1935 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf"); | ||
1936 | } | ||
1937 | GNUNET_assert (0 < sscanf_ret); | ||
1938 | node_connection->namespace_n = namespace_n; | ||
1939 | token = strtok_r (NULL, ":", &rest); | ||
1940 | errno = 0; | ||
1941 | sscanf_ret = sscanf (token, "%u", &node_n); | ||
1942 | if (errno != 0) | ||
1943 | { | ||
1944 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf"); | ||
1945 | } | ||
1946 | GNUNET_assert (0 < sscanf_ret); | ||
1947 | node_connection->node_n = node_n; | ||
1948 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1949 | "node_n %u namespace_n %u node->node_n %u node->namespace_n %u\n", | ||
1950 | node_n, | ||
1951 | namespace_n, | ||
1952 | node->node_n, | ||
1953 | node->namespace_n); | ||
1954 | } | ||
1955 | else | ||
1956 | { | ||
1957 | GNUNET_break (0); | ||
1958 | GNUNET_free (node_connection); | ||
1959 | GNUNET_free (copy); | ||
1960 | return NULL; | ||
1961 | } | ||
1962 | |||
1963 | while (NULL != (token = strtok_r (NULL, ":", &rest))) | ||
1964 | { | ||
1965 | prefix = GNUNET_new (struct GNUNET_TESTING_AddressPrefix); | ||
1966 | token2 = strtok_r (token, "}", &rest2); | ||
1967 | if (NULL != token2) | ||
1968 | prefix->address_prefix = GNUNET_strdup (token2); | ||
1969 | else | ||
1970 | prefix->address_prefix = GNUNET_strdup (token); | ||
1971 | |||
1972 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1973 | "address_prefix %s\n", | ||
1974 | prefix->address_prefix); | ||
1975 | |||
1976 | GNUNET_CONTAINER_DLL_insert (node_connection->address_prefixes_head, | ||
1977 | node_connection->address_prefixes_tail, | ||
1978 | prefix); | ||
1979 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1980 | "address_prefix %s\n", | ||
1981 | prefix->address_prefix); | ||
1982 | } | ||
1983 | |||
1984 | GNUNET_free (copy); | ||
1985 | return node_connection; | ||
1986 | } | ||
1987 | |||
1988 | |||
1989 | /** | ||
1990 | * Every line in the topology configuration starts with a string indicating which | ||
1991 | * kind of information will be configured with this line. Configuration values following | ||
1992 | * this string are seperated by special sequences of characters. A value might be | ||
1993 | * a key value pair. A special key is the 'connect' key. | ||
1994 | * The value is the information about a connections via some protocol to other nodes. | ||
1995 | * Each connection itself is a key value pair separated by the character '|' and | ||
1996 | * surrounded by the characters '{' and '}'. | ||
1997 | * The struct GNUNET_TESTING_NodeConnection holds the information of each connection value. | ||
1998 | * This function extracts the values of each connection into a DLL of | ||
1999 | * struct GNUNET_TESTING_NodeConnection which will be added to a node. | ||
2000 | * | ||
2001 | * @param line The line of configuration. | ||
2002 | * @param node The struct GNUNET_TESTING_NetjailNode to which the DLL of | ||
2003 | * struct GNUNET_TESTING_NodeConnection will be added. | ||
2004 | */ | ||
2005 | static void | ||
2006 | node_connections (const char *line, struct GNUNET_TESTING_NetjailNode *node) | ||
2007 | { | ||
2008 | char *value, *value2; | ||
2009 | char *temp; | ||
2010 | char *copy; | ||
2011 | char *rest = NULL; | ||
2012 | char *rest2 = NULL; | ||
2013 | struct GNUNET_TESTING_NodeConnection *node_connection; | ||
2014 | |||
2015 | |||
2016 | temp = strstr (line, "connect"); | ||
2017 | if (NULL != temp) | ||
2018 | { | ||
2019 | copy = GNUNET_strdup (temp); | ||
2020 | strtok_r (copy, ":", &rest); | ||
2021 | value = strtok_r (rest, "|", &rest2); | ||
2022 | |||
2023 | while (NULL != value) | ||
2024 | { | ||
2025 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2026 | "node_connections value %s\n", | ||
2027 | value); | ||
2028 | node_connection = get_connect_value (value, node); | ||
2029 | if (NULL == node_connection) | ||
2030 | { | ||
2031 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2032 | "connect key was not expected in this configuration line: %s\n", | ||
2033 | line); | ||
2034 | break; | ||
2035 | } | ||
2036 | GNUNET_CONTAINER_DLL_insert (node->node_connections_head, | ||
2037 | node->node_connections_tail, | ||
2038 | node_connection); | ||
2039 | value2 = strstr (value, "}}"); | ||
2040 | if (NULL != value2) | ||
2041 | break; | ||
2042 | value = strtok_r (NULL, "|", &rest2); | ||
2043 | |||
2044 | } | ||
2045 | GNUNET_free (copy); | ||
2046 | } | ||
2047 | } | ||
2048 | |||
2049 | |||
2050 | /** | ||
2051 | * A helper function to log information about individual nodes. | ||
2052 | * | ||
2053 | * @param cls This is not used actually. | ||
2054 | * @param id The key of this value in the map. | ||
2055 | * @param value A struct GNUNET_TESTING_NetjailNode which holds information about a node. | ||
2056 | * return GNUNET_YES to continue with iterating, GNUNET_NO otherwise. | ||
2057 | */ | ||
2058 | static int | ||
2059 | log_nodes (void *cls, const struct GNUNET_ShortHashCode *id, void *value) | ||
2060 | { | ||
2061 | struct GNUNET_TESTING_NetjailNode *node = value; | ||
2062 | struct GNUNET_TESTING_NodeConnection *pos_connection; | ||
2063 | struct GNUNET_TESTING_AddressPrefix *pos_prefix; | ||
2064 | |||
2065 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2066 | "plugin: %s space: %u node: %u global: %u\n", | ||
2067 | node->plugin, | ||
2068 | node->namespace_n, | ||
2069 | node->node_n, | ||
2070 | node->is_global); | ||
2071 | |||
2072 | for (pos_connection = node->node_connections_head; NULL != pos_connection; | ||
2073 | pos_connection = pos_connection->next) | ||
2074 | { | ||
2075 | |||
2076 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2077 | "namespace_n: %u node_n: %u node_type: %u\n", | ||
2078 | pos_connection->namespace_n, | ||
2079 | pos_connection->node_n, | ||
2080 | pos_connection->node_type); | ||
2081 | |||
2082 | for (pos_prefix = pos_connection->address_prefixes_head; NULL != pos_prefix; | ||
2083 | pos_prefix = | ||
2084 | pos_prefix->next) | ||
2085 | { | ||
2086 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2087 | "prefix: %s\n", | ||
2088 | pos_prefix->address_prefix); | ||
2089 | } | ||
2090 | } | ||
2091 | return GNUNET_YES; | ||
2092 | } | ||
2093 | |||
2094 | |||
2095 | /** | ||
2096 | * Helper function to log information about namespaces. | ||
2097 | * | ||
2098 | * @param cls This is not used actually. | ||
2099 | * @param id The key of this value in the map. | ||
2100 | * @param value A struct GNUNET_TESTING_NetjailNamespace which holds information about a subnet. | ||
2101 | * return GNUNET_YES to continue with iterating, GNUNET_NO otherwise. | ||
2102 | */ | ||
2103 | static int | ||
2104 | log_namespaces (void *cls, const struct GNUNET_ShortHashCode *id, void *value) | ||
2105 | { | ||
2106 | struct GNUNET_TESTING_NetjailNamespace *namespace = value; | ||
2107 | |||
2108 | GNUNET_CONTAINER_multishortmap_iterate (namespace->nodes, &log_nodes, NULL); | ||
2109 | return GNUNET_YES; | ||
2110 | } | ||
2111 | |||
2112 | |||
2113 | /** | ||
2114 | * Helper function to log the configuration in case of a problem with configuration. | ||
2115 | * | ||
2116 | * @param topology The struct GNUNET_TESTING_NetjailTopology holding the configuration information. | ||
2117 | */ | ||
2118 | static int | ||
2119 | log_topo (const struct GNUNET_TESTING_NetjailTopology *topology) | ||
2120 | { | ||
2121 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2122 | "plugin: %s spaces: %u nodes: %u known: %u\n", | ||
2123 | topology->plugin, | ||
2124 | topology->namespaces_n, | ||
2125 | topology->nodes_m, | ||
2126 | topology->nodes_x); | ||
2127 | |||
2128 | GNUNET_CONTAINER_multishortmap_iterate (topology->map_namespaces, | ||
2129 | log_namespaces, NULL); | ||
2130 | GNUNET_CONTAINER_multishortmap_iterate (topology->map_globals, &log_nodes, | ||
2131 | NULL); | ||
2132 | return GNUNET_YES; | ||
2133 | } | ||
2134 | |||
2135 | |||
2136 | /** | ||
2137 | * This function extracts information about a specific node from the topology. | ||
2138 | * | ||
2139 | * @param num The global index number of the node. | ||
2140 | * @param[out] node_ex A struct GNUNET_TESTING_NetjailNode with information about the node. | ||
2141 | * @param[out] namespace_ex A struct GNUNET_TESTING_NetjailNamespace with information about the namespace | ||
2142 | the node is in or NULL, if the node is a global node. | ||
2143 | * @param[out] node_connections_ex A struct GNUNET_TESTING_NodeConnection with information about the connection | ||
2144 | of this node to other nodes. | ||
2145 | */ | ||
2146 | static void | ||
2147 | get_node_info (unsigned int num, | ||
2148 | const struct GNUNET_TESTING_NetjailTopology *topology, | ||
2149 | struct GNUNET_TESTING_NetjailNode **node_ex, | ||
2150 | struct GNUNET_TESTING_NetjailNamespace **namespace_ex, | ||
2151 | struct GNUNET_TESTING_NodeConnection **node_connections_ex) | ||
2152 | { | ||
2153 | struct GNUNET_ShortHashCode hkey; | ||
2154 | struct GNUNET_HashCode hc; | ||
2155 | unsigned int namespace_n; | ||
2156 | unsigned int node_m; | ||
2157 | struct GNUNET_TESTING_NetjailNode *node; | ||
2158 | struct GNUNET_TESTING_NetjailNamespace *namespace; | ||
2159 | struct GNUNET_TESTING_NodeConnection *node_connections = NULL; | ||
2160 | |||
2161 | log_topo (topology); | ||
2162 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2163 | "num: %u \n", | ||
2164 | num); | ||
2165 | if (topology->nodes_x >= num) | ||
2166 | { | ||
2167 | |||
2168 | GNUNET_CRYPTO_hash (&num, sizeof(num), &hc); | ||
2169 | memcpy (&hkey, | ||
2170 | &hc, | ||
2171 | sizeof (hkey)); | ||
2172 | node = GNUNET_CONTAINER_multishortmap_get (topology->map_globals, | ||
2173 | &hkey); | ||
2174 | if (NULL != node) | ||
2175 | { | ||
2176 | *node_ex = node; | ||
2177 | *node_connections_ex = node->node_connections_head; | ||
2178 | } | ||
2179 | } | ||
2180 | else | ||
2181 | { | ||
2182 | namespace_n = (unsigned int) ceil ((double) (num - topology->nodes_x) | ||
2183 | / topology->nodes_m); | ||
2184 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2185 | "ceil num: %u nodes_x: %u nodes_m: %u namespace_n: %u\n", | ||
2186 | num, | ||
2187 | topology->nodes_x, | ||
2188 | topology->nodes_m, | ||
2189 | namespace_n); | ||
2190 | GNUNET_CRYPTO_hash (&namespace_n, sizeof(namespace_n), &hc); | ||
2191 | memcpy (&hkey, | ||
2192 | &hc, | ||
2193 | sizeof (hkey)); | ||
2194 | namespace = GNUNET_CONTAINER_multishortmap_get (topology->map_namespaces, | ||
2195 | &hkey); | ||
2196 | if (NULL != namespace) | ||
2197 | { | ||
2198 | node_m = num - topology->nodes_x - topology->nodes_m * (namespace_n - 1); | ||
2199 | GNUNET_CRYPTO_hash (&node_m, sizeof(node_m), &hc); | ||
2200 | memcpy (&hkey, | ||
2201 | &hc, | ||
2202 | sizeof (hkey)); | ||
2203 | node = GNUNET_CONTAINER_multishortmap_get (namespace->nodes, | ||
2204 | &hkey); | ||
2205 | if (NULL != node) | ||
2206 | { | ||
2207 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2208 | "node additional_connects: %u %p\n", | ||
2209 | node->additional_connects, | ||
2210 | node); | ||
2211 | node_connections = node->node_connections_head; | ||
2212 | } | ||
2213 | *node_ex = node; | ||
2214 | *namespace_ex = namespace; | ||
2215 | *node_connections_ex = node_connections; | ||
2216 | } | ||
2217 | } | ||
2218 | } | ||
2219 | |||
2220 | |||
2221 | /** | ||
2222 | * Get a node from the topology. | ||
2223 | * | ||
2224 | * @param num The specific node we want the connections for. | ||
2225 | * @param topology The topology we get the connections from. | ||
2226 | * @return The connections of the node. | ||
2227 | */ | ||
2228 | struct GNUNET_TESTING_NetjailNode * | ||
2229 | GNUNET_TESTING_get_node (unsigned int num, | ||
2230 | struct GNUNET_TESTING_NetjailTopology *topology) | ||
2231 | { | ||
2232 | struct GNUNET_TESTING_NetjailNode *node; | ||
2233 | struct GNUNET_TESTING_NetjailNamespace *namespace; | ||
2234 | struct GNUNET_TESTING_NodeConnection *node_connections; | ||
2235 | |||
2236 | get_node_info (num, topology, &node, &namespace, &node_connections); | ||
2237 | |||
2238 | return node; | ||
2239 | |||
2240 | } | ||
2241 | |||
2242 | |||
2243 | /** | ||
2244 | * Get the connections to other nodes for a specific node. | ||
2245 | * | ||
2246 | * @param num The specific node we want the connections for. | ||
2247 | * @param topology The topology we get the connections from. | ||
2248 | * @return The connections of the node. | ||
2249 | */ | ||
2250 | struct GNUNET_TESTING_NodeConnection * | ||
2251 | GNUNET_TESTING_get_connections (unsigned int num, | ||
2252 | const struct | ||
2253 | GNUNET_TESTING_NetjailTopology *topology) | ||
2254 | { | ||
2255 | struct GNUNET_TESTING_NetjailNode *node; | ||
2256 | struct GNUNET_TESTING_NetjailNamespace *namespace; | ||
2257 | struct GNUNET_TESTING_NodeConnection *node_connections; | ||
2258 | |||
2259 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2260 | "get_connections\n"); | ||
2261 | |||
2262 | get_node_info (num, topology, &node, &namespace, &node_connections); | ||
2263 | |||
2264 | return node_connections; | ||
2265 | } | ||
2266 | |||
2267 | |||
2268 | /** | ||
2269 | * Retrieve the peer identity from the test system with the unique node id. | ||
2270 | * | ||
2271 | * @param num The unique node id. | ||
2272 | * @param tl_system The test system. | ||
2273 | * @return The peer identity wrapping the public key. | ||
2274 | */ | ||
2275 | struct GNUNET_PeerIdentity * | ||
2276 | GNUNET_TESTING_get_peer (unsigned int num, | ||
2277 | const struct GNUNET_TESTING_System *tl_system) | ||
2278 | { | ||
2279 | struct GNUNET_PeerIdentity *peer = GNUNET_new (struct GNUNET_PeerIdentity); | ||
2280 | struct GNUNET_CRYPTO_EddsaPrivateKey *priv_key; | ||
2281 | |||
2282 | priv_key = GNUNET_TESTING_hostkey_get (tl_system, | ||
2283 | num, | ||
2284 | peer); | ||
2285 | |||
2286 | GNUNET_CRYPTO_eddsa_key_get_public (priv_key, | ||
2287 | &peer->public_key); | ||
2288 | GNUNET_free (priv_key); | ||
2289 | return peer; | ||
2290 | } | ||
2291 | |||
2292 | |||
2293 | int | ||
2294 | free_nodes_cb (void *cls, | ||
2295 | const struct GNUNET_ShortHashCode *key, | ||
2296 | void *value) | ||
2297 | { | ||
2298 | (void) cls; | ||
2299 | struct GNUNET_TESTING_NetjailNode *node = value; | ||
2300 | struct GNUNET_TESTING_NodeConnection *pos_connection; | ||
2301 | struct GNUNET_TESTING_AddressPrefix *pos_prefix; | ||
2302 | |||
2303 | while (NULL != (pos_connection = node->node_connections_head)) | ||
2304 | { | ||
2305 | while (NULL != (pos_prefix = pos_connection->address_prefixes_head)) | ||
2306 | { | ||
2307 | GNUNET_CONTAINER_DLL_remove (pos_connection->address_prefixes_head, | ||
2308 | pos_connection->address_prefixes_tail, | ||
2309 | pos_prefix); | ||
2310 | GNUNET_free (pos_prefix->address_prefix); | ||
2311 | GNUNET_free (pos_prefix); | ||
2312 | } | ||
2313 | GNUNET_CONTAINER_DLL_remove (node->node_connections_head, | ||
2314 | node->node_connections_tail, | ||
2315 | pos_connection); | ||
2316 | GNUNET_free (pos_connection); | ||
2317 | } | ||
2318 | |||
2319 | GNUNET_free (node->plugin); | ||
2320 | GNUNET_free (node); | ||
2321 | return GNUNET_OK; | ||
2322 | } | ||
2323 | |||
2324 | |||
2325 | int | ||
2326 | free_namespaces_cb (void *cls, | ||
2327 | const struct GNUNET_ShortHashCode *key, | ||
2328 | void *value) | ||
2329 | { | ||
2330 | (void) cls; | ||
2331 | struct GNUNET_TESTING_NetjailNamespace *namespace = value; | ||
2332 | |||
2333 | GNUNET_free (namespace->router); | ||
2334 | GNUNET_CONTAINER_multishortmap_iterate (namespace->nodes, free_nodes_cb, | ||
2335 | namespace->nodes); | ||
2336 | return GNUNET_OK; | ||
2337 | |||
2338 | } | ||
2339 | |||
2340 | |||
2341 | /** | ||
2342 | * Deallocate memory of the struct GNUNET_TESTING_NetjailTopology. | ||
2343 | * | ||
2344 | * @param topology The GNUNET_TESTING_NetjailTopology to be deallocated. | ||
2345 | */ | ||
2346 | void | ||
2347 | GNUNET_TESTING_free_topology (struct GNUNET_TESTING_NetjailTopology *topology) | ||
2348 | { | ||
2349 | GNUNET_CONTAINER_multishortmap_iterate (topology->map_namespaces, | ||
2350 | free_namespaces_cb, NULL); | ||
2351 | GNUNET_CONTAINER_multishortmap_destroy (topology->map_namespaces); | ||
2352 | GNUNET_CONTAINER_multishortmap_iterate (topology->map_globals, free_nodes_cb, | ||
2353 | NULL); | ||
2354 | GNUNET_CONTAINER_multishortmap_destroy (topology->map_globals); | ||
2355 | GNUNET_free (topology->plugin); | ||
2356 | GNUNET_free (topology); | ||
2357 | } | ||
2358 | |||
2359 | |||
2360 | unsigned int | ||
2361 | GNUNET_TESTING_calculate_num ( | ||
2362 | struct GNUNET_TESTING_NodeConnection *node_connection, | ||
2363 | struct GNUNET_TESTING_NetjailTopology *topology) | ||
2364 | { | ||
2365 | unsigned int n, m, num; | ||
2366 | |||
2367 | n = node_connection->namespace_n; | ||
2368 | m = node_connection->node_n; | ||
2369 | |||
2370 | if (0 == n) | ||
2371 | num = m; | ||
2372 | else | ||
2373 | num = (n - 1) * topology->nodes_m + m + topology->nodes_x; | ||
2374 | |||
2375 | return num; | ||
2376 | } | ||
2377 | |||
2378 | |||
2379 | /** | ||
2380 | * Get the address for a specific communicator from a connection. | ||
2381 | * | ||
2382 | * @param connection The connection we like to have the address from. | ||
2383 | * @param prefix The communicator protocol prefix. | ||
2384 | * @return The address of the communicator. | ||
2385 | */ | ||
2386 | char * | ||
2387 | GNUNET_TESTING_get_address (struct GNUNET_TESTING_NodeConnection *connection, | ||
2388 | const char *prefix) | ||
2389 | { | ||
2390 | struct GNUNET_TESTING_NetjailNode *node; | ||
2391 | char *addr; | ||
2392 | char *template; | ||
2393 | unsigned int node_n; | ||
2394 | |||
2395 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2396 | "get address prefix: %s node_n: %u\n", | ||
2397 | prefix, | ||
2398 | connection->node_n); | ||
2399 | |||
2400 | node = connection->node; | ||
2401 | if (connection->namespace_n == node->namespace_n) | ||
2402 | { | ||
2403 | template = CONNECT_ADDRESS_TEMPLATE; | ||
2404 | node_n = connection->node_n; | ||
2405 | } | ||
2406 | else if (0 == connection->namespace_n) | ||
2407 | { | ||
2408 | template = KNOWN_CONNECT_ADDRESS_TEMPLATE; | ||
2409 | node_n = connection->node_n; | ||
2410 | } | ||
2411 | else if (1 == connection->node_n) | ||
2412 | { | ||
2413 | template = ROUTER_CONNECT_ADDRESS_TEMPLATE; | ||
2414 | node_n = connection->namespace_n; | ||
2415 | } | ||
2416 | else | ||
2417 | { | ||
2418 | return NULL; | ||
2419 | } | ||
2420 | |||
2421 | if (0 == strcmp (PREFIX_TCP, prefix) || | ||
2422 | 0 == strcmp (PREFIX_UDP, prefix) || | ||
2423 | 0 == strcmp (PREFIX_UDP_NATTED, prefix) || | ||
2424 | 0 == strcmp (PREFIX_TCP_NATTED, prefix)) | ||
2425 | { | ||
2426 | GNUNET_asprintf (&addr, | ||
2427 | template, | ||
2428 | prefix, | ||
2429 | node_n); | ||
2430 | } | ||
2431 | else | ||
2432 | { | ||
2433 | GNUNET_assert (0); | ||
2434 | } | ||
2435 | |||
2436 | return addr; | ||
2437 | } | ||
2438 | |||
2439 | |||
2440 | /** | ||
2441 | * Get the number of unintentional additional connections the node waits for. | ||
2442 | * | ||
2443 | * @param num The specific node we want the additional connects for. | ||
2444 | * @return The number of additional connects | ||
2445 | */ | ||
2446 | unsigned int | ||
2447 | GNUNET_TESTING_get_additional_connects (unsigned int num, | ||
2448 | struct GNUNET_TESTING_NetjailTopology * | ||
2449 | topology) | ||
2450 | { | ||
2451 | struct GNUNET_TESTING_NetjailNode *node; | ||
2452 | struct GNUNET_TESTING_NetjailNamespace *namespace; | ||
2453 | struct GNUNET_TESTING_NodeConnection *node_connections; | ||
2454 | |||
2455 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2456 | "get_additional_connects\n"); | ||
2457 | |||
2458 | get_node_info (num, topology, &node, &namespace, &node_connections); | ||
2459 | |||
2460 | if (NULL == node) | ||
2461 | { | ||
2462 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2463 | "No info found for node %d\n", num); | ||
2464 | return 0; | ||
2465 | } | ||
2466 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2467 | "node additional_connects for node %p\n", | ||
2468 | node); | ||
2469 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2470 | "node additional_connects: %u\n", | ||
2471 | node->additional_connects); | ||
2472 | |||
2473 | return node->additional_connects; | ||
2474 | } | ||
2475 | |||
2476 | |||
2477 | static void | ||
2478 | parse_ac (struct GNUNET_TESTING_NetjailNode *p_node, const char *token) | ||
2479 | { | ||
2480 | char *ac_value; | ||
2481 | int ret; | ||
2482 | |||
2483 | ac_value = get_value ("AC", token); | ||
2484 | if (NULL != ac_value) | ||
2485 | { | ||
2486 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2487 | "ac value: %s\n", | ||
2488 | ac_value); | ||
2489 | errno = 0; | ||
2490 | ret = sscanf (ac_value, "%u", &p_node->additional_connects); | ||
2491 | if (errno != 0) | ||
2492 | { | ||
2493 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf"); | ||
2494 | } | ||
2495 | GNUNET_assert (0 < ret); | ||
2496 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2497 | "AC %u\n", | ||
2498 | p_node->additional_connects); | ||
2499 | } | ||
2500 | else | ||
2501 | { | ||
2502 | p_node->additional_connects = 0; | ||
2503 | } | ||
2504 | GNUNET_free (ac_value); | ||
2505 | } | ||
2506 | |||
2507 | |||
2508 | /** | ||
2509 | * Parse the topology data. | ||
2510 | * | ||
2511 | * @param data The topology data. | ||
2512 | * @return The GNUNET_TESTING_NetjailTopology | ||
2513 | */ | ||
2514 | struct GNUNET_TESTING_NetjailTopology * | ||
2515 | GNUNET_TESTING_get_topo_from_string (const char *input) | ||
2516 | { | ||
2517 | char *token; | ||
2518 | char *key = NULL; | ||
2519 | unsigned int out; | ||
2520 | char *rest = NULL; | ||
2521 | char *value = NULL; | ||
2522 | char *value2; | ||
2523 | char *data; | ||
2524 | int ret; | ||
2525 | struct GNUNET_TESTING_NetjailTopology *topo; | ||
2526 | struct GNUNET_TESTING_NetjailRouter *router; | ||
2527 | struct GNUNET_TESTING_NetjailNamespace *namespace; | ||
2528 | struct GNUNET_HashCode hc; | ||
2529 | |||
2530 | data = GNUNET_strdup (input); | ||
2531 | token = strtok_r (data, "\n", &rest); | ||
2532 | topo = GNUNET_new (struct GNUNET_TESTING_NetjailTopology); | ||
2533 | topo->map_namespaces = | ||
2534 | GNUNET_CONTAINER_multishortmap_create (1,GNUNET_NO); | ||
2535 | topo->map_globals = | ||
2536 | GNUNET_CONTAINER_multishortmap_create (1,GNUNET_NO); | ||
2537 | |||
2538 | while (NULL != token) | ||
2539 | { | ||
2540 | if (NULL != key) | ||
2541 | GNUNET_free (key); | ||
2542 | key = get_key (token); | ||
2543 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2544 | "In the loop with token: %s beginning with %s\n", | ||
2545 | token, | ||
2546 | key); | ||
2547 | if (0 == strcmp (key, "M")) | ||
2548 | { | ||
2549 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2550 | "Get first Value for M.\n"); | ||
2551 | out = get_first_value (token); | ||
2552 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2553 | "M: %u\n", | ||
2554 | out); | ||
2555 | topo->nodes_m = out; | ||
2556 | } | ||
2557 | else if (0 == strcmp (key, "N")) | ||
2558 | { | ||
2559 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2560 | "Get first Value for N.\n"); | ||
2561 | out = get_first_value (token); | ||
2562 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2563 | "N: %u\n", | ||
2564 | out); | ||
2565 | topo->namespaces_n = out; | ||
2566 | } | ||
2567 | else if (0 == strcmp (key, "X")) | ||
2568 | { | ||
2569 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2570 | "Get first Value for X.\n"); | ||
2571 | out = get_first_value (token); | ||
2572 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2573 | "X: %u\n", | ||
2574 | out); | ||
2575 | topo->nodes_x = out; | ||
2576 | } | ||
2577 | else if (0 == strcmp (key, "AC")) | ||
2578 | { | ||
2579 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2580 | "Get first Value for AC.\n"); | ||
2581 | out = get_first_value (token); | ||
2582 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2583 | "AC: %u\n", | ||
2584 | out); | ||
2585 | topo->additional_connects = out; | ||
2586 | } | ||
2587 | else if (0 == strcmp (key, "T")) | ||
2588 | { | ||
2589 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2590 | "Get first string value for T.\n"); | ||
2591 | value = get_first_string_value (token); | ||
2592 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2593 | "value: %s\n", | ||
2594 | value); | ||
2595 | topo->plugin = value; | ||
2596 | } | ||
2597 | else if (0 == strcmp (key, "K")) | ||
2598 | { | ||
2599 | struct GNUNET_ShortHashCode hkey_k; | ||
2600 | struct GNUNET_TESTING_NetjailNode *k_node = GNUNET_new (struct | ||
2601 | GNUNET_TESTING_NetjailNode); | ||
2602 | |||
2603 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2604 | "Get first Value for K.\n"); | ||
2605 | out = get_first_value (token); | ||
2606 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2607 | "K: %u\n", | ||
2608 | out); | ||
2609 | k_node->node_n = out; | ||
2610 | GNUNET_CRYPTO_hash (&out, sizeof(out), &hc); | ||
2611 | memcpy (&hkey_k, | ||
2612 | &hc, | ||
2613 | sizeof (hkey_k)); | ||
2614 | k_node->is_global = GNUNET_YES; | ||
2615 | |||
2616 | if (GNUNET_YES == GNUNET_CONTAINER_multishortmap_contains ( | ||
2617 | topo->map_globals, | ||
2618 | &hkey_k)) | ||
2619 | GNUNET_break (0); | ||
2620 | else | ||
2621 | GNUNET_CONTAINER_multishortmap_put (topo->map_globals, | ||
2622 | &hkey_k, | ||
2623 | k_node, | ||
2624 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
2625 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2626 | "Get value for key value on K.\n"); | ||
2627 | value = get_value ("plugin", token); | ||
2628 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2629 | "value: %s\n", | ||
2630 | value); | ||
2631 | k_node->plugin = value; | ||
2632 | parse_ac (k_node, token); | ||
2633 | node_connections (token, k_node); | ||
2634 | GNUNET_free (value); | ||
2635 | } | ||
2636 | else if (0 == strcmp (key, "R")) | ||
2637 | { | ||
2638 | struct GNUNET_ShortHashCode hkey_r; | ||
2639 | router = GNUNET_new (struct GNUNET_TESTING_NetjailRouter); | ||
2640 | |||
2641 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2642 | "Get first Value for R.\n"); | ||
2643 | out = get_first_value (token); | ||
2644 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2645 | "R: %u\n", | ||
2646 | out); | ||
2647 | GNUNET_CRYPTO_hash (&out, sizeof(out), &hc); | ||
2648 | memcpy (&hkey_r, | ||
2649 | &hc, | ||
2650 | sizeof (hkey_r)); | ||
2651 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2652 | "Get value for key tcp_port on R.\n"); | ||
2653 | value = get_value ("tcp_port", token); | ||
2654 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2655 | "tcp_port: %s\n", | ||
2656 | value); | ||
2657 | ret = sscanf (value, "%u", &(router->tcp_port)); | ||
2658 | GNUNET_free (value); | ||
2659 | GNUNET_break (0 != ret && 1 >= router->tcp_port); | ||
2660 | |||
2661 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2662 | "Get value for key udp_port on R.\n"); | ||
2663 | value2 = get_value ("udp_port", token); | ||
2664 | ret = sscanf (value2, "%u", &(router->udp_port)); | ||
2665 | GNUNET_free (value2); | ||
2666 | GNUNET_break (0 != ret && 1 >= router->udp_port); | ||
2667 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2668 | "udp_port: %s\n", | ||
2669 | value2); | ||
2670 | GNUNET_free (value2); | ||
2671 | if (GNUNET_YES == GNUNET_CONTAINER_multishortmap_contains ( | ||
2672 | topo->map_namespaces, | ||
2673 | &hkey_r)) | ||
2674 | { | ||
2675 | namespace = GNUNET_CONTAINER_multishortmap_get (topo->map_namespaces, | ||
2676 | &hkey_r); | ||
2677 | } | ||
2678 | else | ||
2679 | { | ||
2680 | namespace = GNUNET_new (struct GNUNET_TESTING_NetjailNamespace); | ||
2681 | namespace->namespace_n = out; | ||
2682 | namespace->nodes = GNUNET_CONTAINER_multishortmap_create (1,GNUNET_NO); | ||
2683 | GNUNET_CONTAINER_multishortmap_put (topo->map_namespaces, | ||
2684 | &hkey_r, | ||
2685 | namespace, | ||
2686 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
2687 | } | ||
2688 | namespace->router = router; | ||
2689 | |||
2690 | } | ||
2691 | else if (0 == strcmp (key, "P")) | ||
2692 | { | ||
2693 | struct GNUNET_TESTING_NetjailNode *p_node = GNUNET_new (struct | ||
2694 | GNUNET_TESTING_NetjailNode); | ||
2695 | struct GNUNET_ShortHashCode hkey_p; | ||
2696 | |||
2697 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2698 | "Get first Value for P.\n"); | ||
2699 | out = get_first_value (token); | ||
2700 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2701 | "P: %u\n", | ||
2702 | out); | ||
2703 | GNUNET_CRYPTO_hash (&out, sizeof(out), &hc); | ||
2704 | memcpy (&hkey_p, | ||
2705 | &hc, | ||
2706 | sizeof (hkey_p)); | ||
2707 | |||
2708 | if (GNUNET_YES == GNUNET_CONTAINER_multishortmap_contains ( | ||
2709 | topo->map_namespaces, | ||
2710 | &hkey_p)) | ||
2711 | { | ||
2712 | namespace = GNUNET_CONTAINER_multishortmap_get (topo->map_namespaces, | ||
2713 | &hkey_p); | ||
2714 | } | ||
2715 | else | ||
2716 | { | ||
2717 | namespace = GNUNET_new (struct GNUNET_TESTING_NetjailNamespace); | ||
2718 | namespace->nodes = GNUNET_CONTAINER_multishortmap_create (1,GNUNET_NO); | ||
2719 | namespace->namespace_n = out; | ||
2720 | GNUNET_CONTAINER_multishortmap_put (topo->map_namespaces, | ||
2721 | &hkey_p, | ||
2722 | namespace, | ||
2723 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
2724 | } | ||
2725 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2726 | "Get second Value for P.\n"); | ||
2727 | out = get_second_value (token); | ||
2728 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2729 | "P: %u\n", | ||
2730 | out); | ||
2731 | GNUNET_CRYPTO_hash (&out, sizeof(out), &hc); | ||
2732 | memcpy (&hkey_p, | ||
2733 | &hc, | ||
2734 | sizeof (hkey_p)); | ||
2735 | if (GNUNET_YES == GNUNET_CONTAINER_multishortmap_contains ( | ||
2736 | namespace->nodes, | ||
2737 | &hkey_p)) | ||
2738 | { | ||
2739 | GNUNET_break (0); | ||
2740 | } | ||
2741 | else | ||
2742 | { | ||
2743 | |||
2744 | GNUNET_CONTAINER_multishortmap_put (namespace->nodes, | ||
2745 | &hkey_p, | ||
2746 | p_node, | ||
2747 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
2748 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2749 | "Get value for key plugin on P.\n"); | ||
2750 | value = get_value ("plugin", token); | ||
2751 | if (NULL != value) | ||
2752 | { | ||
2753 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2754 | "plugin: %s\n", | ||
2755 | value); | ||
2756 | p_node->plugin = value; | ||
2757 | } | ||
2758 | p_node->node_n = out; | ||
2759 | p_node->namespace_n = namespace->namespace_n; | ||
2760 | } | ||
2761 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2762 | "Get AC Value for P.\n"); | ||
2763 | parse_ac (p_node, token); | ||
2764 | node_connections (token, p_node); | ||
2765 | } | ||
2766 | token = strtok_r (NULL, "\n", &rest); | ||
2767 | if (NULL != token) | ||
2768 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2769 | "Next token %s\n", | ||
2770 | token); | ||
2771 | } | ||
2772 | if (NULL != key) | ||
2773 | GNUNET_free (key); | ||
2774 | GNUNET_free (data); | ||
2775 | return topo; | ||
2776 | } | ||
2777 | |||
2778 | |||
2779 | /** | ||
2780 | * Getting the topology from file. | ||
2781 | * | ||
2782 | * @param filename The name of the topology file. | ||
2783 | * @return The GNUNET_TESTING_NetjailTopology | ||
2784 | */ | ||
2785 | struct GNUNET_TESTING_NetjailTopology * | ||
2786 | GNUNET_TESTING_get_topo_from_file (const char *filename) | ||
2787 | { | ||
2788 | uint64_t fs; | ||
2789 | char *data; | ||
2790 | struct GNUNET_TESTING_NetjailTopology *topo; | ||
2791 | |||
2792 | if (GNUNET_YES != GNUNET_DISK_file_test (filename)) | ||
2793 | { | ||
2794 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2795 | _ ("Topology file %s not found\n"), | ||
2796 | filename); | ||
2797 | return NULL; | ||
2798 | } | ||
2799 | if (GNUNET_OK != | ||
2800 | GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES)) | ||
2801 | { | ||
2802 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2803 | _ ("Topology file %s has no data\n"), | ||
2804 | filename); | ||
2805 | return NULL; | ||
2806 | } | ||
2807 | data = GNUNET_malloc (fs + 1); | ||
2808 | if (fs != GNUNET_DISK_fn_read (filename, data, fs)) | ||
2809 | { | ||
2810 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2811 | _ ("Topology file %s cannot be read\n"), | ||
2812 | filename); | ||
2813 | GNUNET_free (data); | ||
2814 | return NULL; | ||
2815 | } | ||
2816 | |||
2817 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2818 | "file length %" PRIu64 "\n", | ||
2819 | fs); | ||
2820 | data[fs] = '\0'; | ||
2821 | |||
2822 | topo = GNUNET_TESTING_get_topo_from_string (data); | ||
2823 | |||
2824 | GNUNET_free (data); | ||
2825 | |||
2826 | return topo; | ||
2827 | } | ||
2828 | |||
2829 | |||
2830 | /* end of testing.c */ | ||