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
599 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
600 hint.ai_socktype = 0;
601 hint.ai_protocol = 0;
604 hint.ai_canonname = NULL;
606 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
607 port_buckets = system->reserved_ports;
608 for (index = (system->lowport / 32) + 1; index < (system->highport / 32);
611 xor_image = (UINT32_MAX ^ port_buckets[index]);
612 if (0 == xor_image) /* Ports in the bucket are full */
614 pos = system->lowport % 32;
617 if (0 == ((xor_image >> pos) & 1U))
622 open_port = (index * 32) + pos;
623 if (open_port >= system->highport)
625 GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
627 GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
628 GNUNET_free (open_port_str);
629 bind_status = GNUNET_NO;
630 for (ai = ret; NULL != ai; ai = ai->ai_next)
632 socket = GNUNET_NETWORK_socket_create (ai->ai_family, SOCK_STREAM, 0);
636 GNUNET_NETWORK_socket_bind (socket, ai->ai_addr, ai->ai_addrlen);
637 GNUNET_NETWORK_socket_close (socket);
638 if (GNUNET_OK != bind_status)
640 socket = GNUNET_NETWORK_socket_create (ai->ai_family, SOCK_DGRAM, 0);
644 GNUNET_NETWORK_socket_bind (socket, ai->ai_addr, ai->ai_addrlen);
645 GNUNET_NETWORK_socket_close (socket);
646 if (GNUNET_OK != bind_status)
649 port_buckets[index] |= (1U << pos); /* Set the port bit */
651 if (GNUNET_OK == bind_status)
653 LOG (GNUNET_ERROR_TYPE_DEBUG,
654 "Found a free port %u\n",
655 (unsigned int) open_port);
666 * Release reservation of a TCP or UDP port for a peer
667 * (used during #GNUNET_TESTING_peer_destroy()).
669 * @param system system to use for reservation tracking
670 * @param port reserved port to release
673 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
676 uint32_t *port_buckets;
680 port_buckets = system->reserved_ports;
683 LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
684 if (0 == (port_buckets[bucket] & (1U << pos)))
686 GNUNET_break (0); /* Port was not reserved by us using reserve_port() */
689 port_buckets[bucket] &= ~(1U << pos);
694 * Testing includes a number of pre-created hostkeys for
695 * faster peer startup. This function can be used to
696 * access the n-th key of those pre-created hostkeys; note
697 * that these keys are ONLY useful for testing and not
698 * secure as the private keys are part of the public
699 * GNUnet source code.
701 * This is primarily a helper function used internally
702 * by #GNUNET_TESTING_peer_configure.
704 * @param system the testing system handle
705 * @param key_number desired pre-created hostkey to obtain
706 * @param id set to the peer's identity (hash of the public
707 * key; if NULL, NULL is returned immediately
708 * @return NULL on error (not enough keys)
710 struct GNUNET_CRYPTO_EddsaPrivateKey *
711 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
713 struct GNUNET_PeerIdentity *id)
715 struct GNUNET_CRYPTO_EddsaPrivateKey *private_key;
717 if ((NULL == id) || (NULL == system->hostkeys_data))
719 if (key_number >= system->total_hostkeys)
721 LOG (GNUNET_ERROR_TYPE_ERROR,
722 _ ("Key number %u does not exist\n"),
726 private_key = GNUNET_new (struct GNUNET_CRYPTO_EddsaPrivateKey);
727 GNUNET_memcpy (private_key,
728 system->hostkeys_data
729 + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE),
730 GNUNET_TESTING_HOSTKEYFILESIZE);
731 GNUNET_CRYPTO_eddsa_key_get_public (private_key, &id->public_key);
737 * Structure for holding data to build new configurations from a configuration
743 * The system for which we are building configurations
745 struct GNUNET_TESTING_System *system;
748 * The configuration we are building
750 struct GNUNET_CONFIGURATION_Handle *cfg;
753 * The customized service home path for this peer
758 * Array of ports currently allocated to this peer. These ports will be
759 * released upon peer destroy and can be used by other peers which are
765 * The number of ports in the above array
770 * build status - to signal error while building a configuration
777 * Function to iterate over options. Copies
778 * the options to the target configuration,
779 * updating PORT values as needed.
781 * @param cls the UpdateContext
782 * @param section name of the section
783 * @param option name of the option
784 * @param value value of the option
787 update_config (void *cls,
792 struct UpdateContext *uc = cls;
796 char *single_variable;
797 char *per_host_variable;
798 unsigned long long num_per_host;
801 if (GNUNET_OK != uc->status)
803 if (! ((0 == strcmp (option, "PORT")) || (0 == strcmp (option, "UNIXPATH")) ||
804 (0 == strcmp (option, "HOSTNAME"))))
806 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
807 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
808 if ((0 == strcmp (option, "PORT")) && (1 == sscanf (value, "%u", &ival)))
811 (GNUNET_YES != GNUNET_CONFIGURATION_get_value_yesno (uc->cfg,
815 new_port = GNUNET_TESTING_reserve_port (uc->system);
818 uc->status = GNUNET_SYSERR;
819 GNUNET_free (single_variable);
820 GNUNET_free (per_host_variable);
823 GNUNET_snprintf (cval, sizeof(cval), "%u", new_port);
825 GNUNET_array_append (uc->ports, uc->nports, new_port);
827 else if ((ival != 0) &&
829 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg,
832 GNUNET_CONFIGURATION_get_value_number (uc->cfg,
837 /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
838 /* ival + ctx->fdnum % num_per_host); */
840 GNUNET_break (0); /* FIXME */
843 if (0 == strcmp (option, "UNIXPATH"))
845 if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_yesno (uc->cfg,
849 GNUNET_snprintf (uval,
856 else if ((GNUNET_YES ==
857 GNUNET_CONFIGURATION_get_value_number (uc->cfg,
863 GNUNET_break (0); /* FIXME */
866 if (0 == strcmp (option, "HOSTNAME"))
868 value = (NULL == uc->system->hostname) ? "localhost" : uc->system->hostname;
870 GNUNET_free (single_variable);
871 GNUNET_free (per_host_variable);
872 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
877 * Section iterator to set ACCEPT_FROM/ACCEPT_FROM6 to include the address of
878 * 'trusted_hosts' in all sections
880 * @param cls the UpdateContext
881 * @param section name of the section
884 update_config_sections (void *cls, const char *section)
886 struct UpdateContext *uc = cls;
890 char *orig_allowed_hosts;
892 char *ACCEPT_FROM_key;
898 /* Ignore certain options from sections. See
899 https://gnunet.org/bugs/view.php?id=2476 */
901 GNUNET_CONFIGURATION_have_value (uc->cfg, section, "TESTING_IGNORE_KEYS"))
903 GNUNET_assert (GNUNET_YES ==
904 GNUNET_CONFIGURATION_get_value_string (uc->cfg,
906 "TESTING_IGNORE_KEYS",
909 for (ikeys_cnt = 0; NULL != (ptr = strstr (ptr, ";")); ikeys_cnt++)
915 ikeys = GNUNET_malloc ((sizeof(char *)) * ikeys_cnt);
917 for (key = 0; key < ikeys_cnt; key++)
920 ptr = strstr (ptr, ";");
921 GNUNET_assert (NULL != ptr); /* worked just before... */
929 for (key = 0; key < ikeys_cnt; key++)
931 if (NULL != strstr (ikeys[key], "ADVERTISED_PORT"))
934 if ((key == ikeys_cnt) &&
936 GNUNET_CONFIGURATION_have_value (uc->cfg, section, "ADVERTISED_PORT")))
938 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (uc->cfg,
943 GNUNET_CONFIGURATION_set_value_string (uc->cfg,
950 for (key = 0; key < ikeys_cnt; key++)
952 if (NULL != strstr (ikeys[key], "ACCEPT_FROM"))
961 GNUNET_free_non_null (val);
962 ACCEPT_FROM_key = "ACCEPT_FROM";
963 if ((NULL != uc->system->trusted_ip) &&
964 (NULL != strstr (uc->system->trusted_ip, ":"))) /* IPv6 in use */
965 ACCEPT_FROM_key = "ACCEPT_FROM6";
966 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (uc->cfg,
969 &orig_allowed_hosts))
971 orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
973 if (NULL == uc->system->trusted_ip)
974 allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
976 GNUNET_asprintf (&allowed_hosts,
979 uc->system->trusted_ip);
980 GNUNET_free (orig_allowed_hosts);
981 GNUNET_CONFIGURATION_set_value_string (uc->cfg,
985 GNUNET_free (allowed_hosts);
989 static struct SharedServiceInstance *
990 associate_shared_service (struct GNUNET_TESTING_System *system,
991 struct SharedService *ss,
992 struct GNUNET_CONFIGURATION_Handle *cfg)
994 struct SharedServiceInstance *i;
995 struct GNUNET_CONFIGURATION_Handle *temp;
1000 if (((0 == ss->share) && (NULL == ss->instances)) ||
1001 ((0 != ss->share) &&
1002 (ss->n_instances < ((ss->n_peers + ss->share - 1) / ss->share))))
1004 i = GNUNET_new (struct SharedServiceInstance);
1006 (void) GNUNET_asprintf (&gnunet_home,
1011 (void) GNUNET_asprintf (&i->unix_sock, "%s/sock", gnunet_home);
1012 port = GNUNET_TESTING_reserve_port (system);
1015 GNUNET_free (gnunet_home);
1016 cleanup_shared_service_instance (i);
1019 GNUNET_array_append (ss->instances, ss->n_instances, i);
1020 temp = GNUNET_CONFIGURATION_dup (ss->cfg);
1021 (void) GNUNET_asprintf (&i->port_str, "%u", port);
1022 (void) GNUNET_asprintf (&i->cfg_fn, "%s/config", gnunet_home);
1023 GNUNET_CONFIGURATION_set_value_string (temp,
1027 GNUNET_free (gnunet_home);
1028 GNUNET_CONFIGURATION_set_value_string (temp,
1032 GNUNET_CONFIGURATION_set_value_string (temp,
1036 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_write (temp, i->cfg_fn))
1038 GNUNET_CONFIGURATION_destroy (temp);
1039 cleanup_shared_service_instance (i);
1042 GNUNET_CONFIGURATION_destroy (temp);
1046 GNUNET_assert (NULL != ss->instances);
1047 GNUNET_assert (0 < ss->n_instances);
1048 i = ss->instances[ss->n_instances - 1];
1050 GNUNET_CONFIGURATION_iterate_section_values (ss->cfg,
1054 GNUNET_CONFIGURATION_set_value_string (cfg,
1058 GNUNET_CONFIGURATION_set_value_string (cfg, ss->sname, "PORT", i->port_str);
1064 * Create a new configuration using the given configuration as a template;
1065 * ports and paths will be modified to select available ports on the local
1066 * system. The default configuration will be available in PATHS section under
1067 * the option DEFAULTCONFIG after the call. GNUNET_HOME is also set in PATHS
1068 * section to the temporary directory specific to this configuration. If we run
1069 * out of "*port" numbers, return #GNUNET_SYSERR.
1071 * This is primarily a helper function used internally
1072 * by 'GNUNET_TESTING_peer_configure'.
1074 * @param system system to use to coordinate resource usage
1075 * @param cfg template configuration to update
1076 * @param ports array with port numbers used in the created configuration.
1077 * Will be updated upon successful return. Can be NULL
1078 * @param nports the size of the `ports' array. Will be updated.
1079 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - the configuration will
1080 * be incomplete and should not be used there upon
1083 GNUNET_TESTING_configuration_create_ (struct GNUNET_TESTING_System *system,
1084 struct GNUNET_CONFIGURATION_Handle *cfg,
1086 unsigned int *nports)
1088 struct UpdateContext uc;
1089 char *default_config;
1093 uc.status = GNUNET_OK;
1096 GNUNET_asprintf (&uc.gnunet_home,
1099 system->path_counter++);
1100 GNUNET_asprintf (&default_config, "%s/config", uc.gnunet_home);
1101 GNUNET_CONFIGURATION_set_value_string (cfg,
1105 GNUNET_CONFIGURATION_set_value_string (cfg, "arm", "CONFIG", default_config);
1106 GNUNET_free (default_config);
1107 GNUNET_CONFIGURATION_set_value_string (cfg,
1111 /* make PORTs and UNIXPATHs unique */
1112 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
1113 /* allow connections to services from system trusted_ip host */
1114 GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
1115 /* enable loopback-based connections between peers */
1116 GNUNET_CONFIGURATION_set_value_string (cfg, "nat", "USE_LOCALADDR", "YES");
1117 GNUNET_free (uc.gnunet_home);
1118 if ((NULL != ports) && (NULL != nports))
1121 *nports = uc.nports;
1124 GNUNET_free_non_null (uc.ports);
1130 * Create a new configuration using the given configuration as a template;
1131 * ports and paths will be modified to select available ports on the local
1132 * system. The default configuration will be available in PATHS section under
1133 * the option DEFAULTCONFIG after the call. GNUNET_HOME is also set in PATHS
1134 * section to the temporary directory specific to this configuration. If we run
1135 * out of "*port" numbers, return #GNUNET_SYSERR.
1137 * This is primarily a helper function used internally
1138 * by #GNUNET_TESTING_peer_configure().
1140 * @param system system to use to coordinate resource usage
1141 * @param cfg template configuration to update
1142 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - the configuration will
1143 * be incomplete and should not be used there upon
1146 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
1147 struct GNUNET_CONFIGURATION_Handle *cfg)
1149 return GNUNET_TESTING_configuration_create_ (system, cfg, NULL, NULL);
1154 * Configure a GNUnet peer. GNUnet must be installed on the local
1155 * system and available in the PATH.
1157 * @param system system to use to coordinate resource usage
1158 * @param cfg configuration to use; will be UPDATED (to reflect needed
1159 * changes in port numbers and paths)
1160 * @param key_number number of the hostkey to use for the peer
1161 * @param id identifier for the daemon, will be set, can be NULL
1162 * @param emsg set to freshly allocated error message (set to NULL on success),
1164 * @return handle to the peer, NULL on error
1166 struct GNUNET_TESTING_Peer *
1167 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
1168 struct GNUNET_CONFIGURATION_Handle *cfg,
1169 uint32_t key_number,
1170 struct GNUNET_PeerIdentity *id,
1173 struct GNUNET_TESTING_Peer *peer;
1174 struct GNUNET_DISK_FileHandle *fd;
1175 char *hostkey_filename;
1176 char *config_filename;
1177 char *libexec_binary;
1179 struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
1181 struct SharedService *ss;
1182 struct SharedServiceInstance **ss_instances;
1184 unsigned int nports;
1188 ss_instances = NULL;
1191 if (key_number >= system->total_hostkeys)
1196 "You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"),
1197 (unsigned int) system->total_hostkeys);
1202 (NULL == (pk = GNUNET_TESTING_hostkey_get (system, key_number, id))))
1204 GNUNET_asprintf (&emsg_,
1205 _ ("Failed to initialize hostkey for peer %u\n"),
1206 (unsigned int) key_number);
1211 if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (cfg, "PEER", "PRIVATE_KEY"))
1215 _ ("PRIVATE_KEY option in PEER section missing in configuration\n"));
1218 /* Remove sections for shared services */
1219 for (cnt = 0; cnt < system->n_shared_services; cnt++)
1221 ss = system->shared_services[cnt];
1222 GNUNET_CONFIGURATION_remove_section (cfg, ss->sname);
1225 GNUNET_TESTING_configuration_create_ (system, cfg, &ports, &nports))
1227 GNUNET_asprintf (&emsg_,
1228 _ ("Failed to create configuration for peer "
1229 "(not enough free ports?)\n"));
1232 GNUNET_assert (GNUNET_OK ==
1233 GNUNET_CONFIGURATION_get_value_filename (cfg,
1236 &hostkey_filename));
1237 fd = GNUNET_DISK_file_open (hostkey_filename,
1238 GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
1239 GNUNET_DISK_PERM_USER_READ
1240 | GNUNET_DISK_PERM_USER_WRITE);
1243 GNUNET_asprintf (&emsg_,
1244 _ ("Cannot open hostkey file `%s': %s\n"),
1247 GNUNET_free (hostkey_filename);
1250 GNUNET_free (hostkey_filename);
1251 if (GNUNET_TESTING_HOSTKEYFILESIZE !=
1252 GNUNET_DISK_file_write (fd,
1253 system->hostkeys_data
1254 + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE),
1255 GNUNET_TESTING_HOSTKEYFILESIZE))
1257 GNUNET_asprintf (&emsg_,
1258 _ ("Failed to write hostkey file for peer %u: %s\n"),
1259 (unsigned int) key_number,
1261 GNUNET_DISK_file_close (fd);
1264 GNUNET_DISK_file_close (fd);
1265 ss_instances = GNUNET_malloc (sizeof(struct SharedServiceInstance *)
1266 * system->n_shared_services);
1267 for (cnt = 0; cnt < system->n_shared_services; cnt++)
1269 ss = system->shared_services[cnt];
1270 ss_instances[cnt] = associate_shared_service (system, ss, cfg);
1271 if (NULL == ss_instances[cnt])
1273 emsg_ = GNUNET_strdup ("FIXME");
1277 GNUNET_assert (GNUNET_OK ==
1278 GNUNET_CONFIGURATION_get_value_filename (cfg,
1282 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
1284 GNUNET_asprintf (&emsg_,
1286 "Failed to write configuration file `%s' for peer %u: %s\n"),
1288 (unsigned int) key_number,
1290 GNUNET_free (config_filename);
1293 peer = GNUNET_new (struct GNUNET_TESTING_Peer);
1294 peer->ss_instances = ss_instances;
1295 peer->cfgfile = config_filename; /* Free in peer_destroy */
1296 peer->cfg = GNUNET_CONFIGURATION_dup (cfg);
1297 libexec_binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
1298 if (GNUNET_SYSERR ==
1299 GNUNET_CONFIGURATION_get_value_string (cfg,
1302 &peer->main_binary))
1305 GNUNET_asprintf (&peer->main_binary, "%s", libexec_binary);
1306 peer->args = GNUNET_strdup ("");
1310 peer->args = GNUNET_strdup (libexec_binary);
1312 peer->system = system;
1313 peer->key_number = key_number;
1314 GNUNET_free (libexec_binary);
1315 peer->ports = ports; /* Free in peer_destroy */
1316 peer->nports = nports;
1320 GNUNET_free_non_null (ss_instances);
1321 GNUNET_free_non_null (ports);
1322 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
1326 GNUNET_free (emsg_);
1332 * Obtain the peer identity from a peer handle.
1334 * @param peer peer handle for which we want the peer's identity
1335 * @param id identifier for the daemon, will be set
1338 GNUNET_TESTING_peer_get_identity (struct GNUNET_TESTING_Peer *peer,
1339 struct GNUNET_PeerIdentity *id)
1341 if (NULL != peer->id)
1343 GNUNET_memcpy (id, peer->id, sizeof(struct GNUNET_PeerIdentity));
1346 peer->id = GNUNET_new (struct GNUNET_PeerIdentity);
1348 GNUNET_TESTING_hostkey_get (peer->system, peer->key_number, peer->id));
1349 GNUNET_memcpy (id, peer->id, sizeof(struct GNUNET_PeerIdentity));
1356 * @param peer peer to start
1357 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (i.e. peer already running)
1360 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
1362 struct SharedServiceInstance *i;
1365 if (NULL != peer->main_process)
1368 return GNUNET_SYSERR;
1370 GNUNET_assert (NULL != peer->cfgfile);
1371 for (cnt = 0; cnt < peer->system->n_shared_services; cnt++)
1373 i = peer->ss_instances[cnt];
1374 if ((0 == i->n_refs) &&
1375 (GNUNET_SYSERR == start_shared_service_instance (i)))
1376 return GNUNET_SYSERR;
1380 GNUNET_CONFIGURATION_expand_dollar (peer->cfg, peer->main_binary);
1381 peer->main_process =
1382 GNUNET_OS_start_process_s (PIPE_CONTROL,
1383 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
1390 if (NULL == peer->main_process)
1392 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1393 _ ("Failed to start `%s': %s\n"),
1396 return GNUNET_SYSERR;
1403 * Sends SIGTERM to the peer's main process
1405 * @param peer the handle to the peer
1406 * @return #GNUNET_OK if successful; #GNUNET_SYSERR if the main process is NULL
1407 * or upon any error while sending SIGTERM
1410 GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer)
1412 struct SharedServiceInstance *i;
1415 if (NULL == peer->main_process)
1418 return GNUNET_SYSERR;
1420 if (0 != GNUNET_OS_process_kill (peer->main_process, GNUNET_TERM_SIG))
1421 return GNUNET_SYSERR;
1422 for (cnt = 0; cnt < peer->system->n_shared_services; cnt++)
1424 i = peer->ss_instances[cnt];
1425 GNUNET_assert (0 != i->n_refs);
1428 stop_shared_service_instance (i);
1435 * Waits for a peer to terminate. The peer's main process will also be destroyed.
1437 * @param peer the handle to the peer
1438 * @return #GNUNET_OK if successful; #GNUNET_SYSERR if the main process is NULL
1439 * or upon any error while waiting
1442 GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer)
1446 if (NULL == peer->main_process)
1449 return GNUNET_SYSERR;
1451 ret = GNUNET_OS_process_wait (peer->main_process);
1452 GNUNET_OS_process_destroy (peer->main_process);
1453 peer->main_process = NULL;
1461 * @param peer peer to stop
1462 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1465 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
1467 if (GNUNET_SYSERR == GNUNET_TESTING_peer_kill (peer))
1468 return GNUNET_SYSERR;
1469 if (GNUNET_SYSERR == GNUNET_TESTING_peer_wait (peer))
1470 return GNUNET_SYSERR;
1476 * Function called whenever we connect to or disconnect from ARM.
1478 * @param cls closure
1479 * @param connected #GNUNET_YES if connected, #GNUNET_NO if disconnected,
1480 * #GNUNET_SYSERR on error.
1483 disconn_status (void *cls, int connected)
1485 struct GNUNET_TESTING_Peer *peer = cls;
1487 if (GNUNET_SYSERR == connected)
1489 peer->cb (peer->cb_cls, peer, connected);
1492 if (GNUNET_YES == connected)
1494 GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_kill (peer));
1497 GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_wait (peer));
1498 GNUNET_ARM_disconnect (peer->ah);
1500 peer->cb (peer->cb_cls, peer, GNUNET_YES);
1505 * Stop a peer asynchronously using ARM API. Peer's shutdown is signaled
1506 * through the GNUNET_TESTING_PeerStopCallback().
1508 * @param peer the peer to stop
1509 * @param cb the callback to signal peer shutdown
1510 * @param cb_cls closure for the above callback
1511 * @return #GNUNET_OK upon successfully giving the request to the ARM API (this
1512 * does not mean that the peer is successfully stopped); #GNUNET_SYSERR
1516 GNUNET_TESTING_peer_stop_async (struct GNUNET_TESTING_Peer *peer,
1517 GNUNET_TESTING_PeerStopCallback cb,
1520 if (NULL == peer->main_process)
1521 return GNUNET_SYSERR;
1522 peer->ah = GNUNET_ARM_connect (peer->cfg, &disconn_status, peer);
1523 if (NULL == peer->ah)
1524 return GNUNET_SYSERR;
1526 peer->cb_cls = cb_cls;
1532 * Cancel a previous asynchronous peer stop request.
1533 * GNUNET_TESTING_peer_stop_async() should have been called before on the given
1534 * peer. It is an error to call this function if the peer stop callback was
1537 * @param peer the peer on which GNUNET_TESTING_peer_stop_async() was called
1541 GNUNET_TESTING_peer_stop_async_cancel (struct GNUNET_TESTING_Peer *peer)
1543 GNUNET_assert (NULL != peer->ah);
1544 GNUNET_ARM_disconnect (peer->ah);
1550 * Destroy the peer. Releases resources locked during peer configuration.
1551 * If the peer is still running, it will be stopped AND a warning will be
1552 * printed (users of the API should stop the peer explicitly first).
1554 * @param peer peer to destroy
1557 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
1561 if (NULL != peer->main_process)
1562 GNUNET_TESTING_peer_stop (peer);
1563 if (NULL != peer->ah)
1564 GNUNET_ARM_disconnect (peer->ah);
1565 GNUNET_free (peer->cfgfile);
1566 if (NULL != peer->cfg)
1567 GNUNET_CONFIGURATION_destroy (peer->cfg);
1568 GNUNET_free (peer->main_binary);
1569 GNUNET_free (peer->args);
1570 GNUNET_free_non_null (peer->id);
1571 GNUNET_free_non_null (peer->ss_instances);
1572 if (NULL != peer->ports)
1574 for (cnt = 0; cnt < peer->nports; cnt++)
1575 GNUNET_TESTING_release_port (peer->system, peer->ports[cnt]);
1576 GNUNET_free (peer->ports);
1583 * Start a single peer and run a test using the testing library.
1584 * Starts a peer using the given configuration and then invokes the
1585 * given callback. This function ALSO initializes the scheduler loop
1586 * and should thus be called directly from "main". The testcase
1587 * should self-terminate by invoking #GNUNET_SCHEDULER_shutdown().
1589 * @param testdir only the directory name without any path. This is used for
1590 * all service homes; the directory will be created in a temporary
1591 * location depending on the underlying OS
1592 * @param cfgfilename name of the configuration file to use;
1593 * use NULL to only run with defaults
1594 * @param tm main function of the testcase
1595 * @param tm_cls closure for @a tm
1596 * @return 0 on success, 1 on error
1599 GNUNET_TESTING_peer_run (const char *testdir,
1600 const char *cfgfilename,
1601 GNUNET_TESTING_TestMain tm,
1604 return GNUNET_TESTING_service_run (testdir, "arm", cfgfilename, tm, tm_cls);
1609 * Structure for holding service data
1611 struct ServiceContext
1614 * The configuration of the peer in which the service is run
1616 const struct GNUNET_CONFIGURATION_Handle *cfg;
1619 * Callback to signal service startup
1621 GNUNET_TESTING_TestMain tm;
1624 * The peer in which the service is run.
1626 struct GNUNET_TESTING_Peer *peer;
1629 * Closure for the above callback
1636 * Callback to be called when SCHEDULER has been started
1638 * @param cls the ServiceContext
1641 service_run_main (void *cls)
1643 struct ServiceContext *sc = cls;
1645 sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1650 * Start a single service (no ARM, except of course if the given
1651 * service name is 'arm') and run a test using the testing library.
1652 * Starts a service using the given configuration and then invokes the
1653 * given callback. This function ALSO initializes the scheduler loop
1654 * and should thus be called directly from "main". The testcase
1655 * should self-terminate by invoking #GNUNET_SCHEDULER_shutdown().
1657 * This function is useful if the testcase is for a single service
1658 * and if that service doesn't itself depend on other services.
1660 * @param testdir only the directory name without any path. This is used for
1661 * all service homes; the directory will be created in a temporary
1662 * location depending on the underlying OS
1663 * @param service_name name of the service to run
1664 * @param cfgfilename name of the configuration file to use;
1665 * use NULL to only run with defaults
1666 * @param tm main function of the testcase
1667 * @param tm_cls closure for @a tm
1668 * @return 0 on success, 1 on error
1671 GNUNET_TESTING_service_run (const char *testdir,
1672 const char *service_name,
1673 const char *cfgfilename,
1674 GNUNET_TESTING_TestMain tm,
1677 struct ServiceContext sc;
1678 struct GNUNET_TESTING_System *system;
1679 struct GNUNET_TESTING_Peer *peer;
1680 struct GNUNET_CONFIGURATION_Handle *cfg;
1682 char *libexec_binary;
1684 GNUNET_log_setup (testdir, "WARNING", NULL);
1685 system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL, NULL);
1688 cfg = GNUNET_CONFIGURATION_create ();
1689 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1691 LOG (GNUNET_ERROR_TYPE_ERROR,
1692 _ ("Failed to load configuration from %s\n"),
1694 GNUNET_CONFIGURATION_destroy (cfg);
1695 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1698 peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1701 GNUNET_CONFIGURATION_destroy (cfg);
1702 hostkeys_unload (system);
1703 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1706 GNUNET_free (peer->main_binary);
1707 GNUNET_free (peer->args);
1708 GNUNET_asprintf (&binary, "gnunet-service-%s", service_name);
1709 libexec_binary = GNUNET_OS_get_libexec_binary_path (binary);
1710 if (GNUNET_SYSERR ==
1711 GNUNET_CONFIGURATION_get_value_string (cfg,
1714 &peer->main_binary))
1717 GNUNET_asprintf (&peer->main_binary, "%s", libexec_binary);
1718 peer->args = GNUNET_strdup ("");
1721 peer->args = GNUNET_strdup (libexec_binary);
1723 GNUNET_free (libexec_binary);
1724 GNUNET_free (binary);
1725 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1727 GNUNET_TESTING_peer_destroy (peer);
1728 GNUNET_CONFIGURATION_destroy (cfg);
1729 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1736 GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1737 if ((NULL != peer->main_process) &&
1738 (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1740 GNUNET_TESTING_peer_destroy (peer);
1741 GNUNET_CONFIGURATION_destroy (cfg);
1742 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1745 GNUNET_TESTING_peer_destroy (peer);
1746 GNUNET_CONFIGURATION_destroy (cfg);
1747 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1753 * Sometimes we use the binary name to determine which specific
1754 * test to run. In those cases, the string after the last "_"
1755 * in 'argv[0]' specifies a string that determines the configuration
1756 * file or plugin to use.
1758 * This function returns the respective substring, taking care
1759 * of issues such as binaries ending in '.exe' on W32.
1761 * @param argv0 the name of the binary
1762 * @return string between the last '_' and the '.exe' (or the end of the string),
1763 * NULL if argv0 has no '_'
1766 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1768 size_t slen = strlen (argv0) + 1;
1773 GNUNET_memcpy (sbuf, argv0, slen);
1774 ret = strrchr (sbuf, '_');
1777 ret++; /* skip underscore */
1778 dot = strchr (ret, '.');
1781 return GNUNET_strdup (ret);
1785 /* end of testing.c */