2 This file is part of GNUnet
3 Copyright (C) 2008, 2009, 2012 GNUnet e.V.
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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
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
33 #include "gnunet_util_lib.h"
34 #include "gnunet_arm_service.h"
35 #include "gnunet_testing_lib.h"
37 #define LOG(kind, ...) GNUNET_log_from (kind, "testing-api", __VA_ARGS__)
41 * We need pipe control only on WINDOWS
43 #define PIPE_CONTROL GNUNET_NO
47 * Lowest port used for GNUnet testing. Should be high enough to not
48 * conflict with other applications running on the hosts but be low
49 * enough to not conflict with client-ports (typically starting around
52 #define LOW_PORT 12000
55 * Highest port used for GNUnet testing. Should be low enough to not
56 * conflict with the port range for "local" ports (client apps; see
57 * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
59 #define HIGH_PORT 56000
62 struct SharedServiceInstance
64 struct SharedService *ss;
68 struct GNUNET_OS_Process *proc;
81 struct SharedServiceInstance **instances;
83 struct GNUNET_CONFIGURATION_Handle *cfg;
89 unsigned int n_instances;
94 * Handle for a system on which GNUnet peers are executed;
95 * a system is used for reserving unique paths and ports.
97 struct GNUNET_TESTING_System
100 * Prefix (i.e. "/tmp/gnunet-testing/") we prepend to each
106 * The trusted ip. Can either be a single ip address or a network address in
117 * Hostkeys data, contains "GNUNET_TESTING_HOSTKEYFILESIZE * total_hostkeys" bytes.
122 * memory map for @e hostkeys_data.
124 struct GNUNET_DISK_MapHandle *map;
126 struct SharedService **shared_services;
128 unsigned int n_shared_services;
131 * Bitmap where each port that has already been reserved for some GNUnet peer
132 * is recorded. Note that we make no distinction between TCP and UDP ports
133 * and test if a port is already in use before assigning it to a peer/service.
134 * If we detect that a port is already in use, we also mark it in this bitmap.
135 * So all the bits that are zero merely indicate ports that MIGHT be available
138 uint32_t reserved_ports[65536 / 32];
141 * Counter we use to make service home paths unique on this system;
142 * the full path consists of the tmppath and this number. Each
143 * UNIXPATH for a peer is also modified to include the respective
144 * path counter to ensure uniqueness. This field is incremented
145 * by one for each configured peer. Even if peers are destroyed,
146 * we never re-use path counters.
148 uint32_t path_counter;
151 * The number of hostkeys
153 uint32_t total_hostkeys;
156 * Lowest port we are allowed to use.
161 * Highest port we are allowed to use.
168 * Handle for a GNUnet peer controlled by testing.
170 struct GNUNET_TESTING_Peer
173 * The TESTING system associated with this peer
175 struct GNUNET_TESTING_System *system;
178 * Path to the configuration file for this peer.
183 * Binary to be executed during 'GNUNET_TESTING_peer_start'.
184 * Typically 'gnunet-service-arm' (but can be set to a
185 * specific service by 'GNUNET_TESTING_service_run' if
192 * Handle to the running binary of the service, NULL if the
193 * peer/service is currently not running.
195 struct GNUNET_OS_Process *main_process;
198 * The handle to the peer's ARM service
200 struct GNUNET_ARM_Handle *ah;
203 * The config of the peer
205 struct GNUNET_CONFIGURATION_Handle *cfg;
208 * The callback to call asynchronously when a peer is stopped
210 GNUNET_TESTING_PeerStopCallback cb;
213 * The closure for the above callback
218 * The cached identity of this peer. Will be populated on call to
219 * GNUNET_TESTING_peer_get_identity()
221 struct GNUNET_PeerIdentity *id;
223 struct SharedServiceInstance **ss_instances;
226 * Array of ports currently allocated to this peer. These ports will be
227 * released upon peer destroy and can be used by other peers which are
233 * The number of ports in the above array
238 * The keynumber of this peer's hostkey
245 * Testing includes a number of pre-created hostkeys for faster peer
246 * startup. This function loads such keys into memory from a file.
248 * @param system the testing system handle
249 * @return #GNUNET_OK on success; #GNUNET_SYSERR on error
252 hostkeys_load (struct GNUNET_TESTING_System *system)
257 struct GNUNET_DISK_FileHandle *fd;
259 GNUNET_assert (NULL == system->hostkeys_data);
260 data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
261 GNUNET_asprintf (&filename, "%s/testing_hostkeys.ecc", data_dir);
262 GNUNET_free (data_dir);
264 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
266 LOG (GNUNET_ERROR_TYPE_ERROR,
267 _ ("Hostkeys file not found: %s\n"),
269 GNUNET_free (filename);
270 return GNUNET_SYSERR;
272 /* Check hostkey file size, read entire thing into memory */
274 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
278 GNUNET_free (filename);
279 return GNUNET_SYSERR; /* File is empty */
281 if (0 != (fs % GNUNET_TESTING_HOSTKEYFILESIZE))
283 LOG (GNUNET_ERROR_TYPE_ERROR,
284 _ ("Incorrect hostkey file format: %s\n"),
286 GNUNET_free (filename);
287 return GNUNET_SYSERR;
289 fd = GNUNET_DISK_file_open (filename,
290 GNUNET_DISK_OPEN_READ,
291 GNUNET_DISK_PERM_NONE);
294 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename);
295 GNUNET_free (filename);
296 return GNUNET_SYSERR;
298 GNUNET_free (filename);
299 system->hostkeys_data =
300 GNUNET_DISK_file_map (fd, &system->map, GNUNET_DISK_MAP_TYPE_READ, fs);
301 GNUNET_DISK_file_close (fd);
302 if (NULL == system->hostkeys_data)
303 return GNUNET_SYSERR;
304 system->total_hostkeys = fs / GNUNET_TESTING_HOSTKEYFILESIZE;
310 * Function to remove the loaded hostkeys
312 * @param system the testing system handle
315 hostkeys_unload (struct GNUNET_TESTING_System *system)
317 GNUNET_break (NULL != system->hostkeys_data);
318 system->hostkeys_data = NULL;
319 GNUNET_DISK_file_unmap (system->map);
321 system->hostkeys_data = NULL;
322 system->total_hostkeys = 0;
327 * Function to iterate over options.
330 * @param section name of the section
331 * @param option name of the option
332 * @param value value of the option
335 cfg_copy_iterator (void *cls,
340 struct GNUNET_CONFIGURATION_Handle *cfg2 = cls;
342 GNUNET_CONFIGURATION_set_value_string (cfg2, section, option, value);
347 * Create a system handle. There must only be one system
348 * handle per operating system.
350 * @param testdir only the directory name without any path. This is used for
351 * all service homes; the directory will be created in a temporary
352 * location depending on the underlying OS. This variable will be
353 * overridden with the value of the environmental variable
354 * GNUNET_TESTING_PREFIX, if it exists.
355 * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
356 * service configurations generated to allow control connections from
357 * this ip. This can either be a single ip address or a network address
359 * @param hostname the hostname of the system we are using for testing; NULL for
361 * @param shared_services NULL terminated array describing services that are to
362 * be shared among peers
363 * @param lowport lowest port number this system is allowed to allocate (inclusive)
364 * @param highport highest port number this system is allowed to allocate (exclusive)
365 * @return handle to this system, NULL on error
367 struct GNUNET_TESTING_System *
368 GNUNET_TESTING_system_create_with_portrange (
370 const char *trusted_ip,
371 const char *hostname,
372 const struct GNUNET_TESTING_SharedService *shared_services,
376 struct GNUNET_TESTING_System *system;
377 struct GNUNET_TESTING_SharedService tss;
378 struct SharedService *ss;
381 GNUNET_assert (NULL != testdir);
382 system = GNUNET_new (struct GNUNET_TESTING_System);
383 if (NULL == (system->tmppath = getenv (GNUNET_TESTING_PREFIX)))
384 system->tmppath = GNUNET_DISK_mkdtemp (testdir);
386 system->tmppath = GNUNET_strdup (system->tmppath);
387 system->lowport = lowport;
388 system->highport = highport;
389 if (NULL == system->tmppath)
391 GNUNET_free (system);
394 if (NULL != trusted_ip)
395 system->trusted_ip = GNUNET_strdup (trusted_ip);
396 if (NULL != hostname)
397 system->hostname = GNUNET_strdup (hostname);
398 if (GNUNET_OK != hostkeys_load (system))
400 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
403 if (NULL == shared_services)
405 for (cnt = 0; NULL != shared_services[cnt].service; cnt++)
407 tss = shared_services[cnt];
408 ss = GNUNET_new (struct SharedService);
409 ss->sname = GNUNET_strdup (tss.service);
410 ss->cfg = GNUNET_CONFIGURATION_create ();
411 GNUNET_CONFIGURATION_iterate_section_values (tss.cfg,
415 GNUNET_CONFIGURATION_iterate_section_values (tss.cfg,
419 GNUNET_CONFIGURATION_iterate_section_values (tss.cfg,
423 ss->share = tss.share;
424 GNUNET_array_append (system->shared_services,
425 system->n_shared_services,
433 * Create a system handle. There must only be one system handle per operating
434 * system. Uses a default range for allowed ports. Ports are still tested for
437 * @param testdir only the directory name without any path. This is used for all
438 * service homes; the directory will be created in a temporary location
439 * depending on the underlying OS. This variable will be
440 * overridden with the value of the environmental variable
441 * GNUNET_TESTING_PREFIX, if it exists.
442 * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
443 * service configurations generated to allow control connections from
444 * this ip. This can either be a single ip address or a network address
446 * @param hostname the hostname of the system we are using for testing; NULL for
448 * @param shared_services NULL terminated array describing services that are to
449 * be shared among peers
450 * @return handle to this system, NULL on error
452 struct GNUNET_TESTING_System *
453 GNUNET_TESTING_system_create (
455 const char *trusted_ip,
456 const char *hostname,
457 const struct GNUNET_TESTING_SharedService *shared_services)
459 return GNUNET_TESTING_system_create_with_portrange (testdir,
469 cleanup_shared_service_instance (struct SharedServiceInstance *i)
471 if (NULL != i->cfg_fn)
473 (void) unlink (i->cfg_fn);
474 GNUNET_free (i->cfg_fn);
476 GNUNET_free_non_null (i->unix_sock);
477 GNUNET_free_non_null (i->port_str);
478 GNUNET_break (NULL == i->proc);
479 GNUNET_break (0 == i->n_refs);
485 start_shared_service_instance (struct SharedServiceInstance *i)
488 char *libexec_binary;
490 GNUNET_assert (NULL == i->proc);
491 GNUNET_assert (NULL != i->cfg_fn);
492 (void) GNUNET_asprintf (&binary, "gnunet-service-%s", i->ss->sname);
493 libexec_binary = GNUNET_OS_get_libexec_binary_path (binary);
494 GNUNET_free (binary);
495 i->proc = GNUNET_OS_start_process (PIPE_CONTROL,
496 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
505 GNUNET_free (libexec_binary);
507 return GNUNET_SYSERR;
513 stop_shared_service_instance (struct SharedServiceInstance *i)
515 GNUNET_break (0 == i->n_refs);
516 if (0 != GNUNET_OS_process_kill (i->proc, GNUNET_TERM_SIG))
517 LOG (GNUNET_ERROR_TYPE_WARNING,
518 "Killing shared service instance (%s) failed\n",
520 (void) GNUNET_OS_process_wait (i->proc);
521 GNUNET_OS_process_destroy (i->proc);
527 * Free system resources.
529 * @param system system to be freed
530 * @param remove_paths should the 'testdir' and all subdirectories
531 * be removed (clean up on shutdown)?
534 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
537 struct SharedService *ss;
538 struct SharedServiceInstance *i;
542 if (NULL != system->hostkeys_data)
543 hostkeys_unload (system);
544 for (ss_cnt = 0; ss_cnt < system->n_shared_services; ss_cnt++)
546 ss = system->shared_services[ss_cnt];
547 for (i_cnt = 0; i_cnt < ss->n_instances; i_cnt++)
549 i = ss->instances[i_cnt];
551 stop_shared_service_instance (i);
552 cleanup_shared_service_instance (i);
554 GNUNET_free_non_null (ss->instances);
555 GNUNET_CONFIGURATION_destroy (ss->cfg);
556 GNUNET_free (ss->sname);
559 GNUNET_free_non_null (system->shared_services);
560 if (GNUNET_YES == remove_paths)
561 GNUNET_DISK_directory_remove (system->tmppath);
562 GNUNET_free (system->tmppath);
563 GNUNET_free_non_null (system->trusted_ip);
564 GNUNET_free_non_null (system->hostname);
565 GNUNET_free (system);
570 * Reserve a TCP or UDP port for a peer.
572 * @param system system to use for reservation tracking
573 * @return 0 if no free port was available
576 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system)
578 struct GNUNET_NETWORK_Handle *socket;
579 struct addrinfo hint;
580 struct addrinfo *ret;
582 uint32_t *port_buckets;
591 FIXME: Instead of using getaddrinfo we should try to determine the port
592 status by the following heurestics.
594 On systems which support both IPv4 and IPv6, only ports open on both
595 address families are considered open.
596 On system with either IPv4 or IPv6. A port is considered open if it's
597 open in the respective address family
598 */hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
599 hint.ai_socktype = 0;
600 hint.ai_protocol = 0;
603 hint.ai_canonname = NULL;
605 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
606 port_buckets = system->reserved_ports;
607 for (index = (system->lowport / 32) + 1; index < (system->highport / 32);
610 xor_image = (UINT32_MAX ^ port_buckets[index]);
611 if (0 == xor_image) /* Ports in the bucket are full */
613 pos = system->lowport % 32;
616 if (0 == ((xor_image >> pos) & 1U))
621 open_port = (index * 32) + pos;
622 if (open_port >= system->highport)
624 GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
626 GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
627 GNUNET_free (open_port_str);
628 bind_status = GNUNET_NO;
629 for (ai = ret; NULL != ai; ai = ai->ai_next)
631 socket = GNUNET_NETWORK_socket_create (ai->ai_family, SOCK_STREAM, 0);
635 GNUNET_NETWORK_socket_bind (socket, ai->ai_addr, ai->ai_addrlen);
636 GNUNET_NETWORK_socket_close (socket);
637 if (GNUNET_OK != bind_status)
639 socket = GNUNET_NETWORK_socket_create (ai->ai_family, SOCK_DGRAM, 0);
643 GNUNET_NETWORK_socket_bind (socket, ai->ai_addr, ai->ai_addrlen);
644 GNUNET_NETWORK_socket_close (socket);
645 if (GNUNET_OK != bind_status)
648 port_buckets[index] |= (1U << pos); /* Set the port bit */
650 if (GNUNET_OK == bind_status)
652 LOG (GNUNET_ERROR_TYPE_DEBUG,
653 "Found a free port %u\n",
654 (unsigned int) open_port);
665 * Release reservation of a TCP or UDP port for a peer
666 * (used during #GNUNET_TESTING_peer_destroy()).
668 * @param system system to use for reservation tracking
669 * @param port reserved port to release
672 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
675 uint32_t *port_buckets;
679 port_buckets = system->reserved_ports;
682 LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
683 if (0 == (port_buckets[bucket] & (1U << pos)))
685 GNUNET_break (0); /* Port was not reserved by us using reserve_port() */
688 port_buckets[bucket] &= ~(1U << pos);
693 * Testing includes a number of pre-created hostkeys for
694 * faster peer startup. This function can be used to
695 * access the n-th key of those pre-created hostkeys; note
696 * that these keys are ONLY useful for testing and not
697 * secure as the private keys are part of the public
698 * GNUnet source code.
700 * This is primarily a helper function used internally
701 * by #GNUNET_TESTING_peer_configure.
703 * @param system the testing system handle
704 * @param key_number desired pre-created hostkey to obtain
705 * @param id set to the peer's identity (hash of the public
706 * key; if NULL, NULL is returned immediately
707 * @return NULL on error (not enough keys)
709 struct GNUNET_CRYPTO_EddsaPrivateKey *
710 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
712 struct GNUNET_PeerIdentity *id)
714 struct GNUNET_CRYPTO_EddsaPrivateKey *private_key;
716 if ((NULL == id) || (NULL == system->hostkeys_data))
718 if (key_number >= system->total_hostkeys)
720 LOG (GNUNET_ERROR_TYPE_ERROR,
721 _ ("Key number %u does not exist\n"),
725 private_key = GNUNET_new (struct GNUNET_CRYPTO_EddsaPrivateKey);
726 GNUNET_memcpy (private_key,
727 system->hostkeys_data
728 + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE),
729 GNUNET_TESTING_HOSTKEYFILESIZE);
730 GNUNET_CRYPTO_eddsa_key_get_public (private_key, &id->public_key);
736 * Structure for holding data to build new configurations from a configuration
742 * The system for which we are building configurations
744 struct GNUNET_TESTING_System *system;
747 * The configuration we are building
749 struct GNUNET_CONFIGURATION_Handle *cfg;
752 * The customized service home path for this peer
757 * Array of ports currently allocated to this peer. These ports will be
758 * released upon peer destroy and can be used by other peers which are
764 * The number of ports in the above array
769 * build status - to signal error while building a configuration
776 * Function to iterate over options. Copies
777 * the options to the target configuration,
778 * updating PORT values as needed.
780 * @param cls the UpdateContext
781 * @param section name of the section
782 * @param option name of the option
783 * @param value value of the option
786 update_config (void *cls,
791 struct UpdateContext *uc = cls;
795 char *single_variable;
796 char *per_host_variable;
797 unsigned long long num_per_host;
800 if (GNUNET_OK != uc->status)
802 if (! ((0 == strcmp (option, "PORT")) || (0 == strcmp (option, "UNIXPATH")) ||
803 (0 == strcmp (option, "HOSTNAME"))))
805 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
806 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
807 if ((0 == strcmp (option, "PORT")) && (1 == sscanf (value, "%u", &ival)))
810 (GNUNET_YES != GNUNET_CONFIGURATION_get_value_yesno (uc->cfg,
814 new_port = GNUNET_TESTING_reserve_port (uc->system);
817 uc->status = GNUNET_SYSERR;
818 GNUNET_free (single_variable);
819 GNUNET_free (per_host_variable);
822 GNUNET_snprintf (cval, sizeof(cval), "%u", new_port);
824 GNUNET_array_append (uc->ports, uc->nports, new_port);
826 else if ((ival != 0) &&
828 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg,
831 GNUNET_CONFIGURATION_get_value_number (uc->cfg,
836 /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
837 /* ival + ctx->fdnum % num_per_host); */
839 GNUNET_break (0); /* FIXME */
842 if (0 == strcmp (option, "UNIXPATH"))
844 if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_yesno (uc->cfg,
848 GNUNET_snprintf (uval,
855 else if ((GNUNET_YES ==
856 GNUNET_CONFIGURATION_get_value_number (uc->cfg,
862 GNUNET_break (0); /* FIXME */
865 if (0 == strcmp (option, "HOSTNAME"))
867 value = (NULL == uc->system->hostname) ? "localhost" : uc->system->hostname;
869 GNUNET_free (single_variable);
870 GNUNET_free (per_host_variable);
871 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
876 * Section iterator to set ACCEPT_FROM/ACCEPT_FROM6 to include the address of
877 * 'trusted_hosts' in all sections
879 * @param cls the UpdateContext
880 * @param section name of the section
883 update_config_sections (void *cls, const char *section)
885 struct UpdateContext *uc = cls;
889 char *orig_allowed_hosts;
891 char *ACCEPT_FROM_key;
897 /* Ignore certain options from sections. See
898 https://gnunet.org/bugs/view.php?id=2476 */
900 GNUNET_CONFIGURATION_have_value (uc->cfg, section, "TESTING_IGNORE_KEYS"))
902 GNUNET_assert (GNUNET_YES ==
903 GNUNET_CONFIGURATION_get_value_string (uc->cfg,
905 "TESTING_IGNORE_KEYS",
908 for (ikeys_cnt = 0; NULL != (ptr = strstr (ptr, ";")); ikeys_cnt++)
914 ikeys = GNUNET_malloc ((sizeof(char *)) * ikeys_cnt);
916 for (key = 0; key < ikeys_cnt; key++)
919 ptr = strstr (ptr, ";");
920 GNUNET_assert (NULL != ptr); /* worked just before... */
928 for (key = 0; key < ikeys_cnt; key++)
930 if (NULL != strstr (ikeys[key], "ADVERTISED_PORT"))
933 if ((key == ikeys_cnt) &&
935 GNUNET_CONFIGURATION_have_value (uc->cfg, section, "ADVERTISED_PORT")))
937 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (uc->cfg,
942 GNUNET_CONFIGURATION_set_value_string (uc->cfg,
949 for (key = 0; key < ikeys_cnt; key++)
951 if (NULL != strstr (ikeys[key], "ACCEPT_FROM"))
960 GNUNET_free_non_null (val);
961 ACCEPT_FROM_key = "ACCEPT_FROM";
962 if ((NULL != uc->system->trusted_ip) &&
963 (NULL != strstr (uc->system->trusted_ip, ":"))) /* IPv6 in use */
964 ACCEPT_FROM_key = "ACCEPT_FROM6";
965 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (uc->cfg,
968 &orig_allowed_hosts))
970 orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
972 if (NULL == uc->system->trusted_ip)
973 allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
975 GNUNET_asprintf (&allowed_hosts,
978 uc->system->trusted_ip);
979 GNUNET_free (orig_allowed_hosts);
980 GNUNET_CONFIGURATION_set_value_string (uc->cfg,
984 GNUNET_free (allowed_hosts);
988 static struct SharedServiceInstance *
989 associate_shared_service (struct GNUNET_TESTING_System *system,
990 struct SharedService *ss,
991 struct GNUNET_CONFIGURATION_Handle *cfg)
993 struct SharedServiceInstance *i;
994 struct GNUNET_CONFIGURATION_Handle *temp;
999 if (((0 == ss->share) && (NULL == ss->instances)) ||
1000 ((0 != ss->share) &&
1001 (ss->n_instances < ((ss->n_peers + ss->share - 1) / ss->share))))
1003 i = GNUNET_new (struct SharedServiceInstance);
1005 (void) GNUNET_asprintf (&gnunet_home,
1010 (void) GNUNET_asprintf (&i->unix_sock, "%s/sock", gnunet_home);
1011 port = GNUNET_TESTING_reserve_port (system);
1014 GNUNET_free (gnunet_home);
1015 cleanup_shared_service_instance (i);
1018 GNUNET_array_append (ss->instances, ss->n_instances, i);
1019 temp = GNUNET_CONFIGURATION_dup (ss->cfg);
1020 (void) GNUNET_asprintf (&i->port_str, "%u", port);
1021 (void) GNUNET_asprintf (&i->cfg_fn, "%s/config", gnunet_home);
1022 GNUNET_CONFIGURATION_set_value_string (temp,
1026 GNUNET_free (gnunet_home);
1027 GNUNET_CONFIGURATION_set_value_string (temp,
1031 GNUNET_CONFIGURATION_set_value_string (temp,
1035 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_write (temp, i->cfg_fn))
1037 GNUNET_CONFIGURATION_destroy (temp);
1038 cleanup_shared_service_instance (i);
1041 GNUNET_CONFIGURATION_destroy (temp);
1045 GNUNET_assert (NULL != ss->instances);
1046 GNUNET_assert (0 < ss->n_instances);
1047 i = ss->instances[ss->n_instances - 1];
1049 GNUNET_CONFIGURATION_iterate_section_values (ss->cfg,
1053 GNUNET_CONFIGURATION_set_value_string (cfg,
1057 GNUNET_CONFIGURATION_set_value_string (cfg, ss->sname, "PORT", i->port_str);
1063 * Create a new configuration using the given configuration as a template;
1064 * ports and paths will be modified to select available ports on the local
1065 * system. The default configuration will be available in PATHS section under
1066 * the option DEFAULTCONFIG after the call. GNUNET_HOME is also set in PATHS
1067 * section to the temporary directory specific to this configuration. If we run
1068 * out of "*port" numbers, return #GNUNET_SYSERR.
1070 * This is primarily a helper function used internally
1071 * by 'GNUNET_TESTING_peer_configure'.
1073 * @param system system to use to coordinate resource usage
1074 * @param cfg template configuration to update
1075 * @param ports array with port numbers used in the created configuration.
1076 * Will be updated upon successful return. Can be NULL
1077 * @param nports the size of the `ports' array. Will be updated.
1078 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - the configuration will
1079 * be incomplete and should not be used there upon
1082 GNUNET_TESTING_configuration_create_ (struct GNUNET_TESTING_System *system,
1083 struct GNUNET_CONFIGURATION_Handle *cfg,
1085 unsigned int *nports)
1087 struct UpdateContext uc;
1088 char *default_config;
1092 uc.status = GNUNET_OK;
1095 GNUNET_asprintf (&uc.gnunet_home,
1098 system->path_counter++);
1099 GNUNET_asprintf (&default_config, "%s/config", uc.gnunet_home);
1100 GNUNET_CONFIGURATION_set_value_string (cfg,
1104 GNUNET_CONFIGURATION_set_value_string (cfg, "arm", "CONFIG", default_config);
1105 GNUNET_free (default_config);
1106 GNUNET_CONFIGURATION_set_value_string (cfg,
1110 /* make PORTs and UNIXPATHs unique */
1111 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
1112 /* allow connections to services from system trusted_ip host */
1113 GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
1114 /* enable loopback-based connections between peers */
1115 GNUNET_CONFIGURATION_set_value_string (cfg, "nat", "USE_LOCALADDR", "YES");
1116 GNUNET_free (uc.gnunet_home);
1117 if ((NULL != ports) && (NULL != nports))
1120 *nports = uc.nports;
1123 GNUNET_free_non_null (uc.ports);
1129 * Create a new configuration using the given configuration as a template;
1130 * ports and paths will be modified to select available ports on the local
1131 * system. The default configuration will be available in PATHS section under
1132 * the option DEFAULTCONFIG after the call. GNUNET_HOME is also set in PATHS
1133 * section to the temporary directory specific to this configuration. If we run
1134 * out of "*port" numbers, return #GNUNET_SYSERR.
1136 * This is primarily a helper function used internally
1137 * by #GNUNET_TESTING_peer_configure().
1139 * @param system system to use to coordinate resource usage
1140 * @param cfg template configuration to update
1141 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - the configuration will
1142 * be incomplete and should not be used there upon
1145 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
1146 struct GNUNET_CONFIGURATION_Handle *cfg)
1148 return GNUNET_TESTING_configuration_create_ (system, cfg, NULL, NULL);
1153 * Configure a GNUnet peer. GNUnet must be installed on the local
1154 * system and available in the PATH.
1156 * @param system system to use to coordinate resource usage
1157 * @param cfg configuration to use; will be UPDATED (to reflect needed
1158 * changes in port numbers and paths)
1159 * @param key_number number of the hostkey to use for the peer
1160 * @param id identifier for the daemon, will be set, can be NULL
1161 * @param emsg set to freshly allocated error message (set to NULL on success),
1163 * @return handle to the peer, NULL on error
1165 struct GNUNET_TESTING_Peer *
1166 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
1167 struct GNUNET_CONFIGURATION_Handle *cfg,
1168 uint32_t key_number,
1169 struct GNUNET_PeerIdentity *id,
1172 struct GNUNET_TESTING_Peer *peer;
1173 struct GNUNET_DISK_FileHandle *fd;
1174 char *hostkey_filename;
1175 char *config_filename;
1176 char *libexec_binary;
1178 struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
1180 struct SharedService *ss;
1181 struct SharedServiceInstance **ss_instances;
1183 unsigned int nports;
1187 ss_instances = NULL;
1190 if (key_number >= system->total_hostkeys)
1195 "You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"),
1196 (unsigned int) system->total_hostkeys);
1201 (NULL == (pk = GNUNET_TESTING_hostkey_get (system, key_number, id))))
1203 GNUNET_asprintf (&emsg_,
1204 _ ("Failed to initialize hostkey for peer %u\n"),
1205 (unsigned int) key_number);
1210 if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (cfg, "PEER", "PRIVATE_KEY"))
1214 _ ("PRIVATE_KEY option in PEER section missing in configuration\n"));
1217 /* Remove sections for shared services */
1218 for (cnt = 0; cnt < system->n_shared_services; cnt++)
1220 ss = system->shared_services[cnt];
1221 GNUNET_CONFIGURATION_remove_section (cfg, ss->sname);
1224 GNUNET_TESTING_configuration_create_ (system, cfg, &ports, &nports))
1226 GNUNET_asprintf (&emsg_,
1227 _ ("Failed to create configuration for peer "
1228 "(not enough free ports?)\n"));
1231 GNUNET_assert (GNUNET_OK ==
1232 GNUNET_CONFIGURATION_get_value_filename (cfg,
1235 &hostkey_filename));
1236 fd = GNUNET_DISK_file_open (hostkey_filename,
1237 GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
1238 GNUNET_DISK_PERM_USER_READ
1239 | GNUNET_DISK_PERM_USER_WRITE);
1242 GNUNET_asprintf (&emsg_,
1243 _ ("Cannot open hostkey file `%s': %s\n"),
1246 GNUNET_free (hostkey_filename);
1249 GNUNET_free (hostkey_filename);
1250 if (GNUNET_TESTING_HOSTKEYFILESIZE !=
1251 GNUNET_DISK_file_write (fd,
1252 system->hostkeys_data
1253 + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE),
1254 GNUNET_TESTING_HOSTKEYFILESIZE))
1256 GNUNET_asprintf (&emsg_,
1257 _ ("Failed to write hostkey file for peer %u: %s\n"),
1258 (unsigned int) key_number,
1260 GNUNET_DISK_file_close (fd);
1263 GNUNET_DISK_file_close (fd);
1264 ss_instances = GNUNET_malloc (sizeof(struct SharedServiceInstance *)
1265 * system->n_shared_services);
1266 for (cnt = 0; cnt < system->n_shared_services; cnt++)
1268 ss = system->shared_services[cnt];
1269 ss_instances[cnt] = associate_shared_service (system, ss, cfg);
1270 if (NULL == ss_instances[cnt])
1272 emsg_ = GNUNET_strdup ("FIXME");
1276 GNUNET_assert (GNUNET_OK ==
1277 GNUNET_CONFIGURATION_get_value_filename (cfg,
1281 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
1283 GNUNET_asprintf (&emsg_,
1285 "Failed to write configuration file `%s' for peer %u: %s\n"),
1287 (unsigned int) key_number,
1289 GNUNET_free (config_filename);
1292 peer = GNUNET_new (struct GNUNET_TESTING_Peer);
1293 peer->ss_instances = ss_instances;
1294 peer->cfgfile = config_filename; /* Free in peer_destroy */
1295 peer->cfg = GNUNET_CONFIGURATION_dup (cfg);
1296 libexec_binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
1297 if (GNUNET_SYSERR ==
1298 GNUNET_CONFIGURATION_get_value_string (cfg,
1301 &peer->main_binary))
1304 GNUNET_asprintf (&peer->main_binary, "%s", libexec_binary);
1305 peer->args = GNUNET_strdup ("");
1309 peer->args = GNUNET_strdup (libexec_binary);
1311 peer->system = system;
1312 peer->key_number = key_number;
1313 GNUNET_free (libexec_binary);
1314 peer->ports = ports; /* Free in peer_destroy */
1315 peer->nports = nports;
1319 GNUNET_free_non_null (ss_instances);
1320 GNUNET_free_non_null (ports);
1321 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
1325 GNUNET_free (emsg_);
1331 * Obtain the peer identity from a peer handle.
1333 * @param peer peer handle for which we want the peer's identity
1334 * @param id identifier for the daemon, will be set
1337 GNUNET_TESTING_peer_get_identity (struct GNUNET_TESTING_Peer *peer,
1338 struct GNUNET_PeerIdentity *id)
1340 if (NULL != peer->id)
1342 GNUNET_memcpy (id, peer->id, sizeof(struct GNUNET_PeerIdentity));
1345 peer->id = GNUNET_new (struct GNUNET_PeerIdentity);
1347 GNUNET_TESTING_hostkey_get (peer->system, peer->key_number, peer->id));
1348 GNUNET_memcpy (id, peer->id, sizeof(struct GNUNET_PeerIdentity));
1355 * @param peer peer to start
1356 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (i.e. peer already running)
1359 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
1361 struct SharedServiceInstance *i;
1364 if (NULL != peer->main_process)
1367 return GNUNET_SYSERR;
1369 GNUNET_assert (NULL != peer->cfgfile);
1370 for (cnt = 0; cnt < peer->system->n_shared_services; cnt++)
1372 i = peer->ss_instances[cnt];
1373 if ((0 == i->n_refs) &&
1374 (GNUNET_SYSERR == start_shared_service_instance (i)))
1375 return GNUNET_SYSERR;
1379 GNUNET_CONFIGURATION_expand_dollar (peer->cfg, peer->main_binary);
1380 peer->main_process =
1381 GNUNET_OS_start_process_s (PIPE_CONTROL,
1382 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
1389 if (NULL == peer->main_process)
1391 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1392 _ ("Failed to start `%s': %s\n"),
1395 return GNUNET_SYSERR;
1402 * Sends SIGTERM to the peer's main process
1404 * @param peer the handle to the peer
1405 * @return #GNUNET_OK if successful; #GNUNET_SYSERR if the main process is NULL
1406 * or upon any error while sending SIGTERM
1409 GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer)
1411 struct SharedServiceInstance *i;
1414 if (NULL == peer->main_process)
1417 return GNUNET_SYSERR;
1419 if (0 != GNUNET_OS_process_kill (peer->main_process, GNUNET_TERM_SIG))
1420 return GNUNET_SYSERR;
1421 for (cnt = 0; cnt < peer->system->n_shared_services; cnt++)
1423 i = peer->ss_instances[cnt];
1424 GNUNET_assert (0 != i->n_refs);
1427 stop_shared_service_instance (i);
1434 * Waits for a peer to terminate. The peer's main process will also be destroyed.
1436 * @param peer the handle to the peer
1437 * @return #GNUNET_OK if successful; #GNUNET_SYSERR if the main process is NULL
1438 * or upon any error while waiting
1441 GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer)
1445 if (NULL == peer->main_process)
1448 return GNUNET_SYSERR;
1450 ret = GNUNET_OS_process_wait (peer->main_process);
1451 GNUNET_OS_process_destroy (peer->main_process);
1452 peer->main_process = NULL;
1460 * @param peer peer to stop
1461 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1464 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
1466 if (GNUNET_SYSERR == GNUNET_TESTING_peer_kill (peer))
1467 return GNUNET_SYSERR;
1468 if (GNUNET_SYSERR == GNUNET_TESTING_peer_wait (peer))
1469 return GNUNET_SYSERR;
1475 * Function called whenever we connect to or disconnect from ARM.
1477 * @param cls closure
1478 * @param connected #GNUNET_YES if connected, #GNUNET_NO if disconnected,
1479 * #GNUNET_SYSERR on error.
1482 disconn_status (void *cls, int connected)
1484 struct GNUNET_TESTING_Peer *peer = cls;
1486 if (GNUNET_SYSERR == connected)
1488 peer->cb (peer->cb_cls, peer, connected);
1491 if (GNUNET_YES == connected)
1493 GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_kill (peer));
1496 GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_wait (peer));
1497 GNUNET_ARM_disconnect (peer->ah);
1499 peer->cb (peer->cb_cls, peer, GNUNET_YES);
1504 * Stop a peer asynchronously using ARM API. Peer's shutdown is signaled
1505 * through the GNUNET_TESTING_PeerStopCallback().
1507 * @param peer the peer to stop
1508 * @param cb the callback to signal peer shutdown
1509 * @param cb_cls closure for the above callback
1510 * @return #GNUNET_OK upon successfully giving the request to the ARM API (this
1511 * does not mean that the peer is successfully stopped); #GNUNET_SYSERR
1515 GNUNET_TESTING_peer_stop_async (struct GNUNET_TESTING_Peer *peer,
1516 GNUNET_TESTING_PeerStopCallback cb,
1519 if (NULL == peer->main_process)
1520 return GNUNET_SYSERR;
1521 peer->ah = GNUNET_ARM_connect (peer->cfg, &disconn_status, peer);
1522 if (NULL == peer->ah)
1523 return GNUNET_SYSERR;
1525 peer->cb_cls = cb_cls;
1531 * Cancel a previous asynchronous peer stop request.
1532 * GNUNET_TESTING_peer_stop_async() should have been called before on the given
1533 * peer. It is an error to call this function if the peer stop callback was
1536 * @param peer the peer on which GNUNET_TESTING_peer_stop_async() was called
1540 GNUNET_TESTING_peer_stop_async_cancel (struct GNUNET_TESTING_Peer *peer)
1542 GNUNET_assert (NULL != peer->ah);
1543 GNUNET_ARM_disconnect (peer->ah);
1549 * Destroy the peer. Releases resources locked during peer configuration.
1550 * If the peer is still running, it will be stopped AND a warning will be
1551 * printed (users of the API should stop the peer explicitly first).
1553 * @param peer peer to destroy
1556 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
1560 if (NULL != peer->main_process)
1561 GNUNET_TESTING_peer_stop (peer);
1562 if (NULL != peer->ah)
1563 GNUNET_ARM_disconnect (peer->ah);
1564 GNUNET_free (peer->cfgfile);
1565 if (NULL != peer->cfg)
1566 GNUNET_CONFIGURATION_destroy (peer->cfg);
1567 GNUNET_free (peer->main_binary);
1568 GNUNET_free (peer->args);
1569 GNUNET_free_non_null (peer->id);
1570 GNUNET_free_non_null (peer->ss_instances);
1571 if (NULL != peer->ports)
1573 for (cnt = 0; cnt < peer->nports; cnt++)
1574 GNUNET_TESTING_release_port (peer->system, peer->ports[cnt]);
1575 GNUNET_free (peer->ports);
1582 * Start a single peer and run a test using the testing library.
1583 * Starts a peer using the given configuration and then invokes the
1584 * given callback. This function ALSO initializes the scheduler loop
1585 * and should thus be called directly from "main". The testcase
1586 * should self-terminate by invoking #GNUNET_SCHEDULER_shutdown().
1588 * @param testdir only the directory name without any path. This is used for
1589 * all service homes; the directory will be created in a temporary
1590 * location depending on the underlying OS
1591 * @param cfgfilename name of the configuration file to use;
1592 * use NULL to only run with defaults
1593 * @param tm main function of the testcase
1594 * @param tm_cls closure for @a tm
1595 * @return 0 on success, 1 on error
1598 GNUNET_TESTING_peer_run (const char *testdir,
1599 const char *cfgfilename,
1600 GNUNET_TESTING_TestMain tm,
1603 return GNUNET_TESTING_service_run (testdir, "arm", cfgfilename, tm, tm_cls);
1608 * Structure for holding service data
1610 struct ServiceContext
1613 * The configuration of the peer in which the service is run
1615 const struct GNUNET_CONFIGURATION_Handle *cfg;
1618 * Callback to signal service startup
1620 GNUNET_TESTING_TestMain tm;
1623 * The peer in which the service is run.
1625 struct GNUNET_TESTING_Peer *peer;
1628 * Closure for the above callback
1635 * Callback to be called when SCHEDULER has been started
1637 * @param cls the ServiceContext
1640 service_run_main (void *cls)
1642 struct ServiceContext *sc = cls;
1644 sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1649 * Start a single service (no ARM, except of course if the given
1650 * service name is 'arm') and run a test using the testing library.
1651 * Starts a service using the given configuration and then invokes the
1652 * given callback. This function ALSO initializes the scheduler loop
1653 * and should thus be called directly from "main". The testcase
1654 * should self-terminate by invoking #GNUNET_SCHEDULER_shutdown().
1656 * This function is useful if the testcase is for a single service
1657 * and if that service doesn't itself depend on other services.
1659 * @param testdir only the directory name without any path. This is used for
1660 * all service homes; the directory will be created in a temporary
1661 * location depending on the underlying OS
1662 * @param service_name name of the service to run
1663 * @param cfgfilename name of the configuration file to use;
1664 * use NULL to only run with defaults
1665 * @param tm main function of the testcase
1666 * @param tm_cls closure for @a tm
1667 * @return 0 on success, 1 on error
1670 GNUNET_TESTING_service_run (const char *testdir,
1671 const char *service_name,
1672 const char *cfgfilename,
1673 GNUNET_TESTING_TestMain tm,
1676 struct ServiceContext sc;
1677 struct GNUNET_TESTING_System *system;
1678 struct GNUNET_TESTING_Peer *peer;
1679 struct GNUNET_CONFIGURATION_Handle *cfg;
1681 char *libexec_binary;
1683 GNUNET_log_setup (testdir, "WARNING", NULL);
1684 system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL, NULL);
1687 cfg = GNUNET_CONFIGURATION_create ();
1688 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1690 LOG (GNUNET_ERROR_TYPE_ERROR,
1691 _ ("Failed to load configuration from %s\n"),
1693 GNUNET_CONFIGURATION_destroy (cfg);
1694 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1697 peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1700 GNUNET_CONFIGURATION_destroy (cfg);
1701 hostkeys_unload (system);
1702 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1705 GNUNET_free (peer->main_binary);
1706 GNUNET_free (peer->args);
1707 GNUNET_asprintf (&binary, "gnunet-service-%s", service_name);
1708 libexec_binary = GNUNET_OS_get_libexec_binary_path (binary);
1709 if (GNUNET_SYSERR ==
1710 GNUNET_CONFIGURATION_get_value_string (cfg,
1713 &peer->main_binary))
1716 GNUNET_asprintf (&peer->main_binary, "%s", libexec_binary);
1717 peer->args = GNUNET_strdup ("");
1720 peer->args = GNUNET_strdup (libexec_binary);
1722 GNUNET_free (libexec_binary);
1723 GNUNET_free (binary);
1724 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1726 GNUNET_TESTING_peer_destroy (peer);
1727 GNUNET_CONFIGURATION_destroy (cfg);
1728 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1735 GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1736 if ((NULL != peer->main_process) &&
1737 (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1739 GNUNET_TESTING_peer_destroy (peer);
1740 GNUNET_CONFIGURATION_destroy (cfg);
1741 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1744 GNUNET_TESTING_peer_destroy (peer);
1745 GNUNET_CONFIGURATION_destroy (cfg);
1746 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1752 * Sometimes we use the binary name to determine which specific
1753 * test to run. In those cases, the string after the last "_"
1754 * in 'argv[0]' specifies a string that determines the configuration
1755 * file or plugin to use.
1757 * This function returns the respective substring, taking care
1758 * of issues such as binaries ending in '.exe' on W32.
1760 * @param argv0 the name of the binary
1761 * @return string between the last '_' and the '.exe' (or the end of the string),
1762 * NULL if argv0 has no '_'
1765 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1767 size_t slen = strlen (argv0) + 1;
1772 GNUNET_memcpy (sbuf, argv0, slen);
1773 ret = strrchr (sbuf, '_');
1776 ret++; /* skip underscore */
1777 dot = strchr (ret, '.');
1780 return GNUNET_strdup (ret);
1784 /* end of testing.c */