2 This file is part of GNUnet
3 (C) 2008, 2009, 2012 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
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,...) \
38 GNUNET_log_from (kind, "testing-api", __VA_ARGS__)
42 * We need pipe control only on WINDOWS
45 #define PIPE_CONTROL GNUNET_YES
47 #define PIPE_CONTROL GNUNET_NO
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
57 #define LOW_PORT 12000
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).
64 #define HIGH_PORT 56000
68 * Handle for a system on which GNUnet peers are executed;
69 * a system is used for reserving unique paths and ports.
71 struct GNUNET_TESTING_System
74 * Prefix (i.e. "/tmp/gnunet-testing/") we prepend to each
79 * The trusted ip. Can either be a single ip address or a network address in
90 * Hostkeys data, contains "GNUNET_TESTING_HOSTKEYFILESIZE * total_hostkeys" bytes.
95 * memory map for 'hostkeys_data'.
97 struct GNUNET_DISK_MapHandle *map;
100 * File descriptor for the map.
102 struct GNUNET_DISK_FileHandle *map_fd;
105 * Bitmap where each TCP port that has already been reserved for
106 * some GNUnet peer is recorded. Note that we additionally need to
107 * test if a port is already in use by non-GNUnet components before
108 * assigning it to a peer/service. If we detect that a port is
109 * already in use, we also mark it in this bitmap. So all the bits
110 * that are zero merely indicate ports that MIGHT be available for
113 uint32_t reserved_tcp_ports[65536 / 32];
116 * Bitmap where each UDP port that has already been reserved for
117 * some GNUnet peer is recorded. Note that we additionally need to
118 * test if a port is already in use by non-GNUnet components before
119 * assigning it to a peer/service. If we detect that a port is
120 * already in use, we also mark it in this bitmap. So all the bits
121 * that are zero merely indicate ports that MIGHT be available for
124 uint32_t reserved_udp_ports[65536 / 32];
127 * Counter we use to make service home paths unique on this system;
128 * the full path consists of the tmppath and this number. Each
129 * UNIXPATH for a peer is also modified to include the respective
130 * path counter to ensure uniqueness. This field is incremented
131 * by one for each configured peer. Even if peers are destroyed,
132 * we never re-use path counters.
134 uint32_t path_counter;
137 * The number of hostkeys
139 uint32_t total_hostkeys;
142 * Lowest port we are allowed to use.
147 * Highest port we are allowed to use.
154 * Handle for a GNUnet peer controlled by testing.
156 struct GNUNET_TESTING_Peer
159 * The TESTING system associated with this peer
161 struct GNUNET_TESTING_System *system;
164 * Path to the configuration file for this peer.
169 * Binary to be executed during 'GNUNET_TESTING_peer_start'.
170 * Typically 'gnunet-service-arm' (but can be set to a
171 * specific service by 'GNUNET_TESTING_service_run' if
178 * Handle to the running binary of the service, NULL if the
179 * peer/service is currently not running.
181 struct GNUNET_OS_Process *main_process;
184 * The handle to the peer's ARM service
186 struct GNUNET_ARM_Handle *ah;
189 * Handle to ARM monitoring
191 struct GNUNET_ARM_MonitorHandle *mh;
194 * The config of the peer
196 struct GNUNET_CONFIGURATION_Handle *cfg;
199 * The callback to call asynchronously when a peer is stopped
201 GNUNET_TESTING_PeerStopCallback cb;
204 * The closure for the above callback
209 * The cached identity of this peer. Will be populated on call to
210 * GNUNET_TESTING_peer_get_identity()
212 struct GNUNET_PeerIdentity *id;
215 * The keynumber of this peer's hostkey
222 * Testing includes a number of pre-created hostkeys for faster peer
223 * startup. This function loads such keys into memory from a file.
225 * @param system the testing system handle
226 * @return GNUNET_OK on success; GNUNET_SYSERR on error
229 hostkeys_load (struct GNUNET_TESTING_System *system)
235 GNUNET_assert (NULL == system->hostkeys_data);
236 data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
237 GNUNET_asprintf (&filename, "%s/testing_hostkeys.ecc", data_dir);
238 GNUNET_free (data_dir);
240 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
242 LOG (GNUNET_ERROR_TYPE_ERROR,
243 _("Hostkeys file not found: %s\n"), filename);
244 GNUNET_free (filename);
245 return GNUNET_SYSERR;
247 /* Check hostkey file size, read entire thing into memory */
249 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
253 GNUNET_free (filename);
254 return GNUNET_SYSERR; /* File is empty */
256 if (0 != (fs % GNUNET_TESTING_HOSTKEYFILESIZE))
258 LOG (GNUNET_ERROR_TYPE_ERROR,
259 _("Incorrect hostkey file format: %s\n"), filename);
260 GNUNET_free (filename);
261 return GNUNET_SYSERR;
263 system->map_fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
264 GNUNET_DISK_PERM_NONE);
265 if (NULL == system->map_fd)
267 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename);
268 GNUNET_free (filename);
269 return GNUNET_SYSERR;
271 system->total_hostkeys = fs / GNUNET_TESTING_HOSTKEYFILESIZE;
272 system->hostkeys_data = GNUNET_DISK_file_map (system->map_fd,
274 GNUNET_DISK_MAP_TYPE_READ,
276 GNUNET_free (filename);
282 * Function to remove the loaded hostkeys
284 * @param system the testing system handle
287 hostkeys_unload (struct GNUNET_TESTING_System *system)
289 GNUNET_break (NULL != system->hostkeys_data);
290 system->hostkeys_data = NULL;
291 GNUNET_DISK_file_unmap (system->map);
293 GNUNET_DISK_file_close (system->map_fd);
294 system->map_fd = NULL;
295 system->hostkeys_data = NULL;
296 system->total_hostkeys = 0;
301 * Create a system handle. There must only be one system
302 * handle per operating system.
304 * @param testdir only the directory name without any path. This is used for
305 * all service homes; the directory will be created in a temporary
306 * location depending on the underlying OS
307 * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
308 * service configurations generated to allow control connections from
309 * this ip. This can either be a single ip address or a network address
311 * @param hostname the hostname of the system we are using for testing; NULL for
313 * @param lowport lowest port number this system is allowed to allocate (inclusive)
314 * @param highport highest port number this system is allowed to allocate (exclusive)
315 * @return handle to this system, NULL on error
317 struct GNUNET_TESTING_System *
318 GNUNET_TESTING_system_create_with_portrange (const char *testdir,
319 const char *trusted_ip,
320 const char *hostname,
324 struct GNUNET_TESTING_System *system;
326 GNUNET_assert (NULL != testdir);
327 system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
328 system->tmppath = GNUNET_DISK_mkdtemp (testdir);
329 system->lowport = lowport;
330 system->highport = highport;
331 if (NULL == system->tmppath)
333 GNUNET_free (system);
336 if (NULL != trusted_ip)
337 system->trusted_ip = GNUNET_strdup (trusted_ip);
338 if (NULL != hostname)
339 system->hostname = GNUNET_strdup (hostname);
340 if (GNUNET_OK != hostkeys_load (system))
342 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
350 * Create a system handle. There must only be one system handle per operating
351 * system. Uses a default range for allowed ports. Ports are still tested for
354 * @param testdir only the directory name without any path. This is used for all
355 * service homes; the directory will be created in a temporary location
356 * depending on the underlying OS
357 * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
358 * service configurations generated to allow control connections from
359 * this ip. This can either be a single ip address or a network address
361 * @param hostname the hostname of the system we are using for testing; NULL for
363 * @return handle to this system, NULL on error
365 struct GNUNET_TESTING_System *
366 GNUNET_TESTING_system_create (const char *testdir,
367 const char *trusted_ip,
368 const char *hostname)
370 return GNUNET_TESTING_system_create_with_portrange (testdir,
379 * Free system resources.
381 * @param system system to be freed
382 * @param remove_paths should the 'testdir' and all subdirectories
383 * be removed (clean up on shutdown)?
386 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
389 if (NULL != system->hostkeys_data)
390 hostkeys_unload (system);
391 if (GNUNET_YES == remove_paths)
392 GNUNET_DISK_directory_remove (system->tmppath);
393 GNUNET_free (system->tmppath);
394 GNUNET_free_non_null (system->trusted_ip);
395 GNUNET_free_non_null (system->hostname);
396 GNUNET_free (system);
401 * Reserve a TCP or UDP port for a peer.
403 * @param system system to use for reservation tracking
404 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
405 * @return 0 if no free port was available
408 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system,
411 struct GNUNET_NETWORK_Handle *socket;
412 struct addrinfo hint;
413 struct addrinfo *ret;
415 uint32_t *port_buckets;
424 FIXME: Instead of using getaddrinfo we should try to determine the port
425 status by the following heurestics.
427 On systems which support both IPv4 and IPv6, only ports open on both
428 address families are considered open.
429 On system with either IPv4 or IPv6. A port is considered open if it's
430 open in the respective address family
432 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
433 hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM;
434 hint.ai_protocol = 0;
437 hint.ai_canonname = NULL;
439 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
440 port_buckets = (GNUNET_YES == is_tcp) ?
441 system->reserved_tcp_ports : system->reserved_udp_ports;
442 for (index = (system->lowport / 32) + 1; index < (system->highport / 32); index++)
444 xor_image = (UINT32_MAX ^ port_buckets[index]);
445 if (0 == xor_image) /* Ports in the bucket are full */
447 pos = system->lowport % 32;
450 if (0 == ((xor_image >> pos) & 1U))
455 open_port = (index * 32) + pos;
456 if (open_port >= system->highport)
458 GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
460 GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
461 GNUNET_free (open_port_str);
462 bind_status = GNUNET_NO;
463 for (ai = ret; NULL != ai; ai = ai->ai_next)
465 socket = GNUNET_NETWORK_socket_create (ai->ai_family,
466 (GNUNET_YES == is_tcp) ?
467 SOCK_STREAM : SOCK_DGRAM,
471 bind_status = GNUNET_NETWORK_socket_bind (socket,
474 GNUNET_NETWORK_socket_close (socket);
475 if (GNUNET_OK != bind_status)
478 port_buckets[index] |= (1U << pos); /* Set the port bit */
480 if (GNUNET_OK == bind_status)
482 LOG (GNUNET_ERROR_TYPE_DEBUG,
483 "Found a free port %u\n", (unsigned int) open_port);
494 * Release reservation of a TCP or UDP port for a peer
495 * (used during GNUNET_TESTING_peer_destroy).
497 * @param system system to use for reservation tracking
498 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
499 * @param port reserved port to release
502 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
506 uint32_t *port_buckets;
510 port_buckets = (GNUNET_YES == is_tcp) ?
511 system->reserved_tcp_ports : system->reserved_udp_ports;
514 LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
515 if (0 == (port_buckets[bucket] & (1U << pos)))
517 GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
520 port_buckets[bucket] &= ~(1U << pos);
525 * Testing includes a number of pre-created hostkeys for
526 * faster peer startup. This function can be used to
527 * access the n-th key of those pre-created hostkeys; note
528 * that these keys are ONLY useful for testing and not
529 * secure as the private keys are part of the public
530 * GNUnet source code.
532 * This is primarily a helper function used internally
533 * by 'GNUNET_TESTING_peer_configure'.
535 * @param system the testing system handle
536 * @param key_number desired pre-created hostkey to obtain
537 * @param id set to the peer's identity (hash of the public
538 * key; if NULL, GNUNET_SYSERR is returned immediately
539 * @return NULL on error (not enough keys)
541 struct GNUNET_CRYPTO_EccPrivateKey *
542 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
544 struct GNUNET_PeerIdentity *id)
546 struct GNUNET_CRYPTO_EccPrivateKey *private_key;
547 struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded public_key;
549 if ((NULL == id) || (NULL == system->hostkeys_data))
551 if (key_number >= system->total_hostkeys)
553 LOG (GNUNET_ERROR_TYPE_ERROR,
554 _("Key number %u does not exist\n"), key_number);
557 private_key = GNUNET_CRYPTO_ecc_decode_key (system->hostkeys_data +
559 GNUNET_TESTING_HOSTKEYFILESIZE),
560 GNUNET_TESTING_HOSTKEYFILESIZE,
562 if (NULL == private_key)
564 LOG (GNUNET_ERROR_TYPE_ERROR,
565 _("Error while decoding key %u\n"), key_number);
568 GNUNET_CRYPTO_ecc_key_get_public (private_key, &public_key);
569 GNUNET_CRYPTO_hash (&public_key,
570 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
577 * Structure for holding data to build new configurations from a configuration
583 * The system for which we are building configurations
585 struct GNUNET_TESTING_System *system;
588 * The configuration we are building
590 struct GNUNET_CONFIGURATION_Handle *cfg;
593 * The customized service home path for this peer
598 * build status - to signal error while building a configuration
605 * Function to iterate over options. Copies
606 * the options to the target configuration,
607 * updating PORT values as needed.
609 * @param cls the UpdateContext
610 * @param section name of the section
611 * @param option name of the option
612 * @param value value of the option
615 update_config (void *cls, const char *section, const char *option,
618 struct UpdateContext *uc = cls;
622 char *single_variable;
623 char *per_host_variable;
624 unsigned long long num_per_host;
627 if (GNUNET_OK != uc->status)
629 if (! ((0 == strcmp (option, "PORT"))
630 || (0 == strcmp (option, "UNIXPATH"))
631 || (0 == strcmp (option, "HOSTNAME"))))
633 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
634 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
635 if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
639 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
642 /* FIXME: What about UDP? */
643 new_port = GNUNET_TESTING_reserve_port (uc->system, GNUNET_YES);
646 uc->status = GNUNET_SYSERR;
647 GNUNET_free (single_variable);
648 GNUNET_free (per_host_variable);
651 GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
654 else if ((ival != 0) &&
656 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
658 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
662 /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
663 /* ival + ctx->fdnum % num_per_host); */
665 GNUNET_break (0); /* FIXME */
668 if (0 == strcmp (option, "UNIXPATH"))
671 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
674 GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock",
675 uc->service_home, section);
678 else if ((GNUNET_YES ==
679 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
684 GNUNET_break(0); /* FIXME */
687 if (0 == strcmp (option, "HOSTNAME"))
689 value = (NULL == uc->system->hostname) ? "localhost" : uc->system->hostname;
691 GNUNET_free (single_variable);
692 GNUNET_free (per_host_variable);
693 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
698 * Section iterator to set ACCEPT_FROM/ACCEPT_FROM6 to include the address of
699 * 'trusted_hosts' in all sections
701 * @param cls the UpdateContext
702 * @param section name of the section
705 update_config_sections (void *cls,
708 struct UpdateContext *uc = cls;
712 char *orig_allowed_hosts;
714 char *ACCEPT_FROM_key;
720 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
721 "TESTING_IGNORE_KEYS"))
725 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section,
726 "TESTING_IGNORE_KEYS", &val));
728 for (ikeys_cnt = 0; NULL != (ptr = strstr (ptr, ";")); ikeys_cnt++)
734 ikeys = GNUNET_malloc ((sizeof (char *)) * ikeys_cnt);
736 for (key = 0; key < ikeys_cnt; key++)
739 ptr = strstr (ptr, ";");
747 for (key = 0; key < ikeys_cnt; key++)
749 if (NULL != strstr (ikeys[key], "ADVERTISED_PORT"))
752 if ((key == ikeys_cnt) &&
753 (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
757 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "PORT", &ptr))
759 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section,
760 "ADVERTISED_PORT", ptr);
764 for (key = 0; key < ikeys_cnt; key++)
766 if (NULL != strstr (ikeys[key], "ACCEPT_FROM"))
775 GNUNET_free_non_null (val);
776 ACCEPT_FROM_key = "ACCEPT_FROM";
777 if ((NULL != uc->system->trusted_ip) &&
778 (NULL != strstr (uc->system->trusted_ip, ":"))) /* IPv6 in use */
779 ACCEPT_FROM_key = "ACCEPT_FROM6";
781 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, ACCEPT_FROM_key,
782 &orig_allowed_hosts))
784 orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
786 if (NULL == uc->system->trusted_ip)
787 allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
789 GNUNET_asprintf (&allowed_hosts, "%s%s;", orig_allowed_hosts,
790 uc->system->trusted_ip);
791 GNUNET_free (orig_allowed_hosts);
792 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, ACCEPT_FROM_key,
794 GNUNET_free (allowed_hosts);
799 * Create a new configuration using the given configuration as a template;
800 * ports and paths will be modified to select available ports on the local
801 * system. The default configuration will be available in PATHS section under
802 * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS
803 * section to the temporary directory specific to this configuration. If we run
804 * out of "*port" numbers, return SYSERR.
806 * This is primarily a helper function used internally
807 * by 'GNUNET_TESTING_peer_configure'.
809 * @param system system to use to coordinate resource usage
810 * @param cfg template configuration to update
811 * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
812 * be incomplete and should not be used there upon
815 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
816 struct GNUNET_CONFIGURATION_Handle *cfg)
818 struct UpdateContext uc;
819 char *default_config;
823 uc.status = GNUNET_OK;
824 GNUNET_asprintf (&uc.service_home, "%s/%u", system->tmppath,
825 system->path_counter++);
826 GNUNET_asprintf (&default_config, "%s/config", uc.service_home);
827 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
829 GNUNET_CONFIGURATION_set_value_string (cfg, "arm", "CONFIG",
831 GNUNET_free (default_config);
832 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME",
834 /* make PORTs and UNIXPATHs unique */
835 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
836 /* allow connections to services from system trusted_ip host */
837 GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
838 /* enable loopback-based connections between peers */
839 GNUNET_CONFIGURATION_set_value_string (cfg,
841 "USE_LOCALADDR", "YES");
842 GNUNET_free (uc.service_home);
848 * Configure a GNUnet peer. GNUnet must be installed on the local
849 * system and available in the PATH.
851 * @param system system to use to coordinate resource usage
852 * @param cfg configuration to use; will be UPDATED (to reflect needed
853 * changes in port numbers and paths)
854 * @param key_number number of the hostkey to use for the peer
855 * @param id identifier for the daemon, will be set, can be NULL
856 * @param emsg set to freshly allocated error message (set to NULL on success),
858 * @return handle to the peer, NULL on error
860 struct GNUNET_TESTING_Peer *
861 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
862 struct GNUNET_CONFIGURATION_Handle *cfg,
864 struct GNUNET_PeerIdentity *id,
867 struct GNUNET_TESTING_Peer *peer;
868 struct GNUNET_DISK_FileHandle *fd;
870 char hostkey_filename[128];
871 char *config_filename;
872 char *libexec_binary;
874 struct GNUNET_CRYPTO_EccPrivateKey *pk;
878 if (GNUNET_OK != GNUNET_TESTING_configuration_create (system, cfg))
880 GNUNET_asprintf (&emsg_,
881 _("Failed to create configuration for peer (not enough free ports?)\n"));
882 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
889 if (key_number >= system->total_hostkeys)
891 GNUNET_asprintf (&emsg_,
892 _("You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"),
893 (unsigned int) system->total_hostkeys);
894 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
903 (NULL == (pk = GNUNET_TESTING_hostkey_get (system, key_number, id))))
905 GNUNET_asprintf (&emsg_,
906 _("Failed to initialize hostkey for peer %u\n"),
907 (unsigned int) key_number);
908 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
916 GNUNET_CRYPTO_ecc_key_free (pk);
917 GNUNET_assert (GNUNET_OK ==
918 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
921 /* FIXME: might be better to evaluate actual configuration option here... */
922 GNUNET_snprintf (hostkey_filename, sizeof (hostkey_filename), "%s/private.ecc",
924 GNUNET_free (service_home);
925 fd = GNUNET_DISK_file_open (hostkey_filename,
926 GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
927 GNUNET_DISK_PERM_USER_READ
928 | GNUNET_DISK_PERM_USER_WRITE);
934 if (GNUNET_TESTING_HOSTKEYFILESIZE !=
935 GNUNET_DISK_file_write (fd, system->hostkeys_data
936 + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE),
937 GNUNET_TESTING_HOSTKEYFILESIZE))
939 GNUNET_asprintf (&emsg_,
940 _("Failed to write hostkey file for peer %u: %s\n"),
941 (unsigned int) key_number,
943 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
948 GNUNET_DISK_file_close (fd);
951 GNUNET_DISK_file_close (fd);
952 GNUNET_assert (GNUNET_OK ==
953 GNUNET_CONFIGURATION_get_value_string
954 (cfg, "PATHS", "DEFAULTCONFIG", &config_filename));
955 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
957 GNUNET_asprintf (&emsg_,
958 _("Failed to write configuration file `%s' for peer %u: %s\n"),
960 (unsigned int) key_number,
962 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
967 GNUNET_free (config_filename);
970 peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
971 peer->cfgfile = config_filename; /* Free in peer_destroy */
972 peer->cfg = GNUNET_CONFIGURATION_dup (cfg);
973 libexec_binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
974 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "arm", "PREFIX", &peer->main_binary))
977 GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
978 peer->args = strdup ("");
981 peer->args = strdup (libexec_binary);
982 peer->system = system;
983 peer->key_number = key_number;
984 GNUNET_free (libexec_binary);
990 * Obtain the peer identity from a peer handle.
992 * @param peer peer handle for which we want the peer's identity
993 * @param id identifier for the daemon, will be set
996 GNUNET_TESTING_peer_get_identity (struct GNUNET_TESTING_Peer *peer,
997 struct GNUNET_PeerIdentity *id)
999 if (NULL != peer->id)
1001 memcpy (id, peer->id, sizeof (struct GNUNET_PeerIdentity));
1004 peer->id = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
1005 GNUNET_CRYPTO_ecc_key_free (GNUNET_TESTING_hostkey_get (peer->system,
1008 memcpy (id, peer->id, sizeof (struct GNUNET_PeerIdentity));
1015 * @param peer peer to start
1016 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
1019 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
1021 if (NULL != peer->main_process)
1024 return GNUNET_SYSERR;
1026 GNUNET_assert (NULL != peer->cfgfile);
1027 peer->main_process = GNUNET_OS_start_process (PIPE_CONTROL,
1028 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
1036 if (NULL == peer->main_process)
1038 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1039 _("Failed to start `%s': %s\n"),
1042 return GNUNET_SYSERR;
1049 * Start a service at a peer using its ARM service
1051 * @param peer the peer whose service has to be started
1052 * @param service_name name of the service to start
1053 * @param timeout how long should the ARM API try to send the request to start
1055 * @param cont the callback to call with result and status from ARM API
1056 * @param cont_cls the closure for the above callback
1057 * @return GNUNET_OK upon successfully queuing the service start request;
1058 * GNUNET_SYSERR upon error
1061 GNUNET_TESTING_peer_service_start (struct GNUNET_TESTING_Peer *peer,
1062 const char *service_name,
1063 struct GNUNET_TIME_Relative timeout,
1064 GNUNET_ARM_ResultCallback cont,
1067 if (NULL == peer->ah)
1068 return GNUNET_SYSERR;
1069 GNUNET_ARM_request_service_start (peer->ah,
1071 GNUNET_OS_INHERIT_STD_ALL,
1079 * Stop a service at a peer using its ARM service
1081 * @param peer the peer whose service has to be stopped
1082 * @param service_name name of the service to stop
1083 * @param timeout how long should the ARM API try to send the request to stop
1085 * @param cont the callback to call with result and status from ARM API
1086 * @param cont_cls the closure for the above callback
1087 * @return GNUNET_OK upon successfully queuing the service stop request;
1088 * GNUNET_SYSERR upon error
1091 GNUNET_TESTING_peer_service_stop (struct GNUNET_TESTING_Peer *peer,
1092 const char *service_name,
1093 struct GNUNET_TIME_Relative timeout,
1094 GNUNET_ARM_ResultCallback cont,
1097 if (NULL == peer->ah)
1098 return GNUNET_SYSERR;
1099 GNUNET_ARM_request_service_stop (peer->ah,
1108 * Sends SIGTERM to the peer's main process
1110 * @param peer the handle to the peer
1111 * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1112 * or upon any error while sending SIGTERM
1115 GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer)
1117 if (NULL == peer->main_process)
1120 return GNUNET_SYSERR;
1122 return (0 == GNUNET_OS_process_kill (peer->main_process, SIGTERM)) ?
1123 GNUNET_OK : GNUNET_SYSERR;
1128 * Waits for a peer to terminate. The peer's main process will also be destroyed.
1130 * @param peer the handle to the peer
1131 * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1132 * or upon any error while waiting
1135 GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer)
1139 if (NULL == peer->main_process)
1142 return GNUNET_SYSERR;
1144 ret = GNUNET_OS_process_wait (peer->main_process);
1145 GNUNET_OS_process_destroy (peer->main_process);
1146 peer->main_process = NULL;
1154 * @param peer peer to stop
1155 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1158 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
1160 if (GNUNET_SYSERR == GNUNET_TESTING_peer_kill (peer))
1161 return GNUNET_SYSERR;
1162 if (GNUNET_SYSERR == GNUNET_TESTING_peer_wait (peer))
1163 return GNUNET_SYSERR;
1169 * Function called whenever we connect to or disconnect from ARM.
1171 * @param cls closure
1172 * @param arm handle to the ARM connection
1173 * @param connected GNUNET_YES if connected, GNUNET_NO if disconnected,
1174 * GNUNET_SYSERR on error.
1177 disconn_status (void *cls, struct GNUNET_ARM_Handle *arm,
1180 struct GNUNET_TESTING_Peer *peer = cls;
1182 if (GNUNET_SYSERR == connected)
1184 peer->cb (peer->cb_cls, peer, connected);
1187 if (GNUNET_YES == connected)
1189 GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_kill (peer));
1192 GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_wait (peer));
1193 GNUNET_ARM_disconnect_and_free (peer->ah);
1195 peer->cb (peer->cb_cls, peer, GNUNET_YES);
1200 * Stop a peer asynchronously using ARM API. Peer's shutdown is signaled
1201 * through the GNUNET_TESTING_PeerStopCallback().
1203 * @param peer the peer to stop
1204 * @param cb the callback to signal peer shutdown
1205 * @param cb_cls closure for the above callback
1206 * @return GNUNET_OK upon successfully giving the request to the ARM API (this
1207 * does not mean that the peer is successfully stopped); GNUNET_SYSERR
1211 GNUNET_TESTING_peer_stop_async (struct GNUNET_TESTING_Peer *peer,
1212 GNUNET_TESTING_PeerStopCallback cb,
1215 if (NULL == peer->main_process)
1216 return GNUNET_SYSERR;
1217 peer->ah = GNUNET_ARM_connect (peer->cfg, &disconn_status, peer);
1218 if (NULL == peer->ah)
1219 return GNUNET_SYSERR;
1221 peer->cb_cls = cb_cls;
1227 * Destroy the peer. Releases resources locked during peer configuration.
1228 * If the peer is still running, it will be stopped AND a warning will be
1229 * printed (users of the API should stop the peer explicitly first).
1231 * @param peer peer to destroy
1234 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
1236 if (NULL != peer->main_process)
1237 GNUNET_TESTING_peer_stop (peer);
1238 if (NULL != peer->ah)
1239 GNUNET_ARM_disconnect_and_free (peer->ah);
1240 if (NULL != peer->mh)
1241 GNUNET_ARM_monitor_disconnect_and_free (peer->mh);
1242 GNUNET_free (peer->cfgfile);
1243 if (NULL != peer->cfg)
1244 GNUNET_CONFIGURATION_destroy (peer->cfg);
1245 GNUNET_free (peer->main_binary);
1246 GNUNET_free (peer->args);
1247 GNUNET_free_non_null (peer->id);
1253 * Start a single peer and run a test using the testing library.
1254 * Starts a peer using the given configuration and then invokes the
1255 * given callback. This function ALSO initializes the scheduler loop
1256 * and should thus be called directly from "main". The testcase
1257 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1259 * @param testdir only the directory name without any path. This is used for
1260 * all service homes; the directory will be created in a temporary
1261 * location depending on the underlying OS
1262 * @param cfgfilename name of the configuration file to use;
1263 * use NULL to only run with defaults
1264 * @param tm main function of the testcase
1265 * @param tm_cls closure for 'tm'
1266 * @return 0 on success, 1 on error
1269 GNUNET_TESTING_peer_run (const char *testdir,
1270 const char *cfgfilename,
1271 GNUNET_TESTING_TestMain tm,
1274 return GNUNET_TESTING_service_run (testdir, "arm",
1275 cfgfilename, tm, tm_cls);
1280 * Structure for holding service data
1282 struct ServiceContext
1285 * The configuration of the peer in which the service is run
1287 const struct GNUNET_CONFIGURATION_Handle *cfg;
1290 * Callback to signal service startup
1292 GNUNET_TESTING_TestMain tm;
1295 * The peer in which the service is run.
1297 struct GNUNET_TESTING_Peer *peer;
1300 * Closure for the above callback
1307 * Callback to be called when SCHEDULER has been started
1309 * @param cls the ServiceContext
1310 * @param tc the TaskContext
1313 service_run_main (void *cls,
1314 const struct GNUNET_SCHEDULER_TaskContext *tc)
1316 struct ServiceContext *sc = cls;
1318 sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1323 * Start a single service (no ARM, except of course if the given
1324 * service name is 'arm') and run a test using the testing library.
1325 * Starts a service using the given configuration and then invokes the
1326 * given callback. This function ALSO initializes the scheduler loop
1327 * and should thus be called directly from "main". The testcase
1328 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1330 * This function is useful if the testcase is for a single service
1331 * and if that service doesn't itself depend on other services.
1333 * @param testdir only the directory name without any path. This is used for
1334 * all service homes; the directory will be created in a temporary
1335 * location depending on the underlying OS
1336 * @param service_name name of the service to run
1337 * @param cfgfilename name of the configuration file to use;
1338 * use NULL to only run with defaults
1339 * @param tm main function of the testcase
1340 * @param tm_cls closure for 'tm'
1341 * @return 0 on success, 1 on error
1344 GNUNET_TESTING_service_run (const char *testdir,
1345 const char *service_name,
1346 const char *cfgfilename,
1347 GNUNET_TESTING_TestMain tm,
1350 struct ServiceContext sc;
1351 struct GNUNET_TESTING_System *system;
1352 struct GNUNET_TESTING_Peer *peer;
1353 struct GNUNET_CONFIGURATION_Handle *cfg;
1355 char *libexec_binary;
1357 GNUNET_log_setup (testdir, "WARNING", NULL);
1358 system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL);
1361 cfg = GNUNET_CONFIGURATION_create ();
1362 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1364 LOG (GNUNET_ERROR_TYPE_ERROR,
1365 _("Failed to load configuration from %s\n"), cfgfilename);
1366 GNUNET_CONFIGURATION_destroy (cfg);
1367 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1370 peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1373 GNUNET_CONFIGURATION_destroy (cfg);
1374 hostkeys_unload (system);
1375 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1378 GNUNET_free (peer->main_binary);
1379 GNUNET_free (peer->args);
1380 GNUNET_asprintf (&binary, "gnunet-service-%s", service_name);
1381 libexec_binary = GNUNET_OS_get_libexec_binary_path (binary);
1382 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, service_name, "PREFIX", &peer->main_binary))
1385 GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1386 peer->args = strdup ("");
1389 peer->args = strdup (libexec_binary);
1391 GNUNET_free (libexec_binary);
1392 GNUNET_free (binary);
1393 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1395 GNUNET_TESTING_peer_destroy (peer);
1396 GNUNET_CONFIGURATION_destroy (cfg);
1397 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1404 GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1405 if ((NULL != peer->main_process) &&
1406 (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1408 GNUNET_TESTING_peer_destroy (peer);
1409 GNUNET_CONFIGURATION_destroy (cfg);
1410 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1413 GNUNET_TESTING_peer_destroy (peer);
1414 GNUNET_CONFIGURATION_destroy (cfg);
1415 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1421 * Sometimes we use the binary name to determine which specific
1422 * test to run. In those cases, the string after the last "_"
1423 * in 'argv[0]' specifies a string that determines the configuration
1424 * file or plugin to use.
1426 * This function returns the respective substring, taking care
1427 * of issues such as binaries ending in '.exe' on W32.
1429 * @param argv0 the name of the binary
1430 * @return string between the last '_' and the '.exe' (or the end of the string),
1431 * NULL if argv0 has no '_'
1434 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1436 size_t slen = strlen (argv0) + 1;
1441 memcpy (sbuf, argv0, slen);
1442 ret = strrchr (sbuf, '_');
1445 ret++; /* skip underscore */
1446 dot = strchr (ret, '.');
1449 return GNUNET_strdup (ret);
1453 /* end of testing.c */