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