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 * The config of the peer
191 struct GNUNET_CONFIGURATION_Handle *cfg;
193 GNUNET_TESTING_PeerStartCallback cb;
197 struct GNUNET_ARM_MonitorHandle *mh;
200 * The cached identity of this peer. Will be populated on call to
201 * GNUNET_TESTING_peer_get_identity()
203 struct GNUNET_PeerIdentity *id;
206 * The keynumber of this peer's hostkey
213 * Testing includes a number of pre-created hostkeys for faster peer
214 * startup. This function loads such keys into memory from a file.
216 * @param system the testing system handle
217 * @return GNUNET_OK on success; GNUNET_SYSERR on error
220 hostkeys_load (struct GNUNET_TESTING_System *system)
226 GNUNET_assert (NULL == system->hostkeys_data);
227 data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
228 GNUNET_asprintf (&filename, "%s/testing_hostkeys.ecc", data_dir);
229 GNUNET_free (data_dir);
231 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
233 LOG (GNUNET_ERROR_TYPE_ERROR,
234 _("Hostkeys file not found: %s\n"), filename);
235 GNUNET_free (filename);
236 return GNUNET_SYSERR;
238 /* Check hostkey file size, read entire thing into memory */
240 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
244 GNUNET_free (filename);
245 return GNUNET_SYSERR; /* File is empty */
247 if (0 != (fs % GNUNET_TESTING_HOSTKEYFILESIZE))
249 LOG (GNUNET_ERROR_TYPE_ERROR,
250 _("Incorrect hostkey file format: %s\n"), filename);
251 GNUNET_free (filename);
252 return GNUNET_SYSERR;
254 system->map_fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
255 GNUNET_DISK_PERM_NONE);
256 if (NULL == system->map_fd)
258 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename);
259 GNUNET_free (filename);
260 return GNUNET_SYSERR;
262 system->total_hostkeys = fs / GNUNET_TESTING_HOSTKEYFILESIZE;
263 system->hostkeys_data = GNUNET_DISK_file_map (system->map_fd,
265 GNUNET_DISK_MAP_TYPE_READ,
267 GNUNET_free (filename);
273 * Function to remove the loaded hostkeys
275 * @param system the testing system handle
278 hostkeys_unload (struct GNUNET_TESTING_System *system)
280 GNUNET_break (NULL != system->hostkeys_data);
281 system->hostkeys_data = NULL;
282 GNUNET_DISK_file_unmap (system->map);
284 GNUNET_DISK_file_close (system->map_fd);
285 system->map_fd = NULL;
286 system->hostkeys_data = NULL;
287 system->total_hostkeys = 0;
292 * Create a system handle. There must only be one system
293 * handle per operating system.
295 * @param testdir only the directory name without any path. This is used for
296 * all service homes; the directory will be created in a temporary
297 * location depending on the underlying OS
298 * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
299 * service configurations generated to allow control connections from
300 * this ip. This can either be a single ip address or a network address
302 * @param hostname the hostname of the system we are using for testing; NULL for
304 * @param lowport lowest port number this system is allowed to allocate (inclusive)
305 * @param highport highest port number this system is allowed to allocate (exclusive)
306 * @return handle to this system, NULL on error
308 struct GNUNET_TESTING_System *
309 GNUNET_TESTING_system_create_with_portrange (const char *testdir,
310 const char *trusted_ip,
311 const char *hostname,
315 struct GNUNET_TESTING_System *system;
317 GNUNET_assert (NULL != testdir);
318 system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
319 system->tmppath = GNUNET_DISK_mkdtemp (testdir);
320 system->lowport = lowport;
321 system->highport = highport;
322 if (NULL == system->tmppath)
324 GNUNET_free (system);
327 if (NULL != trusted_ip)
328 system->trusted_ip = GNUNET_strdup (trusted_ip);
329 if (NULL != hostname)
330 system->hostname = GNUNET_strdup (hostname);
331 if (GNUNET_OK != hostkeys_load (system))
333 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
341 * Create a system handle. There must only be one system handle per operating
342 * system. Uses a default range for allowed ports. Ports are still tested for
345 * @param testdir only the directory name without any path. This is used for all
346 * service homes; the directory will be created in a temporary location
347 * depending on the underlying OS
348 * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
349 * service configurations generated to allow control connections from
350 * this ip. This can either be a single ip address or a network address
352 * @param hostname the hostname of the system we are using for testing; NULL for
354 * @return handle to this system, NULL on error
356 struct GNUNET_TESTING_System *
357 GNUNET_TESTING_system_create (const char *testdir,
358 const char *trusted_ip,
359 const char *hostname)
361 return GNUNET_TESTING_system_create_with_portrange (testdir,
370 * Free system resources.
372 * @param system system to be freed
373 * @param remove_paths should the 'testdir' and all subdirectories
374 * be removed (clean up on shutdown)?
377 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
380 if (NULL != system->hostkeys_data)
381 hostkeys_unload (system);
382 if (GNUNET_YES == remove_paths)
383 GNUNET_DISK_directory_remove (system->tmppath);
384 GNUNET_free (system->tmppath);
385 GNUNET_free_non_null (system->trusted_ip);
386 GNUNET_free_non_null (system->hostname);
387 GNUNET_free (system);
392 * Reserve a TCP or UDP port for a peer.
394 * @param system system to use for reservation tracking
395 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
396 * @return 0 if no free port was available
399 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system,
402 struct GNUNET_NETWORK_Handle *socket;
403 struct addrinfo hint;
404 struct addrinfo *ret;
406 uint32_t *port_buckets;
415 FIXME: Instead of using getaddrinfo we should try to determine the port
416 status by the following heurestics.
418 On systems which support both IPv4 and IPv6, only ports open on both
419 address families are considered open.
420 On system with either IPv4 or IPv6. A port is considered open if it's
421 open in the respective address family
423 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
424 hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM;
425 hint.ai_protocol = 0;
428 hint.ai_canonname = NULL;
430 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
431 port_buckets = (GNUNET_YES == is_tcp) ?
432 system->reserved_tcp_ports : system->reserved_udp_ports;
433 for (index = (system->lowport / 32) + 1; index < (system->highport / 32); index++)
435 xor_image = (UINT32_MAX ^ port_buckets[index]);
436 if (0 == xor_image) /* Ports in the bucket are full */
438 pos = system->lowport % 32;
441 if (0 == ((xor_image >> pos) & 1U))
446 open_port = (index * 32) + pos;
447 if (open_port >= system->highport)
449 GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
451 GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
452 GNUNET_free (open_port_str);
453 bind_status = GNUNET_NO;
454 for (ai = ret; NULL != ai; ai = ai->ai_next)
456 socket = GNUNET_NETWORK_socket_create (ai->ai_family,
457 (GNUNET_YES == is_tcp) ?
458 SOCK_STREAM : SOCK_DGRAM,
462 bind_status = GNUNET_NETWORK_socket_bind (socket,
465 GNUNET_NETWORK_socket_close (socket);
466 if (GNUNET_OK != bind_status)
469 port_buckets[index] |= (1U << pos); /* Set the port bit */
471 if (GNUNET_OK == bind_status)
473 LOG (GNUNET_ERROR_TYPE_DEBUG,
474 "Found a free port %u\n", (unsigned int) open_port);
485 * Release reservation of a TCP or UDP port for a peer
486 * (used during GNUNET_TESTING_peer_destroy).
488 * @param system system to use for reservation tracking
489 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
490 * @param port reserved port to release
493 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
497 uint32_t *port_buckets;
501 port_buckets = (GNUNET_YES == is_tcp) ?
502 system->reserved_tcp_ports : system->reserved_udp_ports;
505 LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
506 if (0 == (port_buckets[bucket] & (1U << pos)))
508 GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
511 port_buckets[bucket] &= ~(1U << pos);
516 * Reserve a SERVICEHOME path for a peer.
518 * @param system system to use for reservation tracking
519 * @return NULL on error, otherwise fresh unique path to use
520 * as the servicehome for the peer; must be freed by the caller
524 reserve_path (struct GNUNET_TESTING_System *system)
528 GNUNET_asprintf (&reserved_path,
529 "%s/%u", system->tmppath, system->path_counter++);
530 return reserved_path;
535 * Testing includes a number of pre-created hostkeys for
536 * faster peer startup. This function can be used to
537 * access the n-th key of those pre-created hostkeys; note
538 * that these keys are ONLY useful for testing and not
539 * secure as the private keys are part of the public
540 * GNUnet source code.
542 * This is primarily a helper function used internally
543 * by 'GNUNET_TESTING_peer_configure'.
545 * @param system the testing system handle
546 * @param key_number desired pre-created hostkey to obtain
547 * @param id set to the peer's identity (hash of the public
548 * key; if NULL, GNUNET_SYSERR is returned immediately
549 * @return NULL on error (not enough keys)
551 struct GNUNET_CRYPTO_EccPrivateKey *
552 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
554 struct GNUNET_PeerIdentity *id)
556 struct GNUNET_CRYPTO_EccPrivateKey *private_key;
557 struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded public_key;
559 if ((NULL == id) || (NULL == system->hostkeys_data))
561 if (key_number >= system->total_hostkeys)
563 LOG (GNUNET_ERROR_TYPE_ERROR,
564 _("Key number %u does not exist\n"), key_number);
567 private_key = GNUNET_CRYPTO_ecc_decode_key (system->hostkeys_data +
569 GNUNET_TESTING_HOSTKEYFILESIZE),
570 GNUNET_TESTING_HOSTKEYFILESIZE,
572 if (NULL == private_key)
574 LOG (GNUNET_ERROR_TYPE_ERROR,
575 _("Error while decoding key %u\n"), key_number);
578 GNUNET_CRYPTO_ecc_key_get_public (private_key, &public_key);
579 GNUNET_CRYPTO_hash (&public_key,
580 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
587 * Structure for holding data to build new configurations from a configuration
593 * The system for which we are building configurations
595 struct GNUNET_TESTING_System *system;
598 * The configuration we are building
600 struct GNUNET_CONFIGURATION_Handle *cfg;
603 * The customized service home path for this peer
608 * build status - to signal error while building a configuration
615 * Function to iterate over options. Copies
616 * the options to the target configuration,
617 * updating PORT values as needed.
619 * @param cls the UpdateContext
620 * @param section name of the section
621 * @param option name of the option
622 * @param value value of the option
625 update_config (void *cls, const char *section, const char *option,
628 struct UpdateContext *uc = cls;
632 char *single_variable;
633 char *per_host_variable;
634 unsigned long long num_per_host;
637 if (GNUNET_OK != uc->status)
639 if (! ((0 == strcmp (option, "PORT"))
640 || (0 == strcmp (option, "UNIXPATH"))
641 || (0 == strcmp (option, "HOSTNAME"))))
643 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
644 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
645 if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
649 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
652 /* FIXME: What about UDP? */
653 new_port = GNUNET_TESTING_reserve_port (uc->system, GNUNET_YES);
656 uc->status = GNUNET_SYSERR;
657 GNUNET_free (single_variable);
658 GNUNET_free (per_host_variable);
661 GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
664 else if ((ival != 0) &&
666 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
668 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
672 /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
673 /* ival + ctx->fdnum % num_per_host); */
675 GNUNET_break (0); /* FIXME */
678 if (0 == strcmp (option, "UNIXPATH"))
681 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
684 GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock",
685 uc->service_home, section);
688 else if ((GNUNET_YES ==
689 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
694 GNUNET_break(0); /* FIXME */
697 if (0 == strcmp (option, "HOSTNAME"))
699 value = (NULL == uc->system->hostname) ? "localhost" : uc->system->hostname;
701 GNUNET_free (single_variable);
702 GNUNET_free (per_host_variable);
703 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
708 * Section iterator to set ACCEPT_FROM/ACCEPT_FROM6 to include the address of
709 * 'trusted_hosts' in all sections
711 * @param cls the UpdateContext
712 * @param section name of the section
715 update_config_sections (void *cls,
718 struct UpdateContext *uc = cls;
722 char *orig_allowed_hosts;
724 char *ACCEPT_FROM_key;
730 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
731 "TESTING_IGNORE_KEYS"))
735 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section,
736 "TESTING_IGNORE_KEYS", &val));
738 for (ikeys_cnt = 0; NULL != (ptr = strstr (ptr, ";")); ikeys_cnt++)
744 ikeys = GNUNET_malloc ((sizeof (char *)) * ikeys_cnt);
746 for (key = 0; key < ikeys_cnt; key++)
749 ptr = strstr (ptr, ";");
757 for (key = 0; key < ikeys_cnt; key++)
759 if (NULL != strstr (ikeys[key], "ADVERTISED_PORT"))
762 if ((key == ikeys_cnt) &&
763 (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
767 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "PORT", &ptr))
769 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section,
770 "ADVERTISED_PORT", ptr);
774 for (key = 0; key < ikeys_cnt; key++)
776 if (NULL != strstr (ikeys[key], "ACCEPT_FROM"))
785 GNUNET_free_non_null (val);
786 ACCEPT_FROM_key = "ACCEPT_FROM";
787 if ((NULL != uc->system->trusted_ip) &&
788 (NULL != strstr (uc->system->trusted_ip, ":"))) /* IPv6 in use */
789 ACCEPT_FROM_key = "ACCEPT_FROM6";
791 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, ACCEPT_FROM_key,
792 &orig_allowed_hosts))
794 orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
796 if (NULL == uc->system->trusted_ip)
797 allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
799 GNUNET_asprintf (&allowed_hosts, "%s%s;", orig_allowed_hosts,
800 uc->system->trusted_ip);
801 GNUNET_free (orig_allowed_hosts);
802 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, ACCEPT_FROM_key,
804 GNUNET_free (allowed_hosts);
809 * Create a new configuration using the given configuration as a template;
810 * ports and paths will be modified to select available ports on the local
811 * system. The default configuration will be available in PATHS section under
812 * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS
813 * section to the temporary directory specific to this configuration. If we run
814 * out of "*port" numbers, return SYSERR.
816 * This is primarily a helper function used internally
817 * by 'GNUNET_TESTING_peer_configure'.
819 * @param system system to use to coordinate resource usage
820 * @param cfg template configuration to update
821 * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
822 * be incomplete and should not be used there upon
825 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
826 struct GNUNET_CONFIGURATION_Handle *cfg)
828 struct UpdateContext uc;
829 char *default_config;
833 uc.status = GNUNET_OK;
834 GNUNET_asprintf (&uc.service_home, "%s/%u", system->tmppath,
835 system->path_counter++);
836 GNUNET_asprintf (&default_config, "%s/config", uc.service_home);
837 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
839 GNUNET_CONFIGURATION_set_value_string (cfg, "arm", "CONFIG",
841 GNUNET_free (default_config);
842 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME",
844 /* make PORTs and UNIXPATHs unique */
845 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
846 /* allow connections to services from system trusted_ip host */
847 GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
848 /* enable loopback-based connections between peers */
849 GNUNET_CONFIGURATION_set_value_string (cfg,
851 "USE_LOCALADDR", "YES");
852 GNUNET_free (uc.service_home);
858 * Configure a GNUnet peer. GNUnet must be installed on the local
859 * system and available in the PATH.
861 * @param system system to use to coordinate resource usage
862 * @param cfg configuration to use; will be UPDATED (to reflect needed
863 * changes in port numbers and paths)
864 * @param key_number number of the hostkey to use for the peer
865 * @param id identifier for the daemon, will be set, can be NULL
866 * @param emsg set to freshly allocated error message (set to NULL on success),
868 * @return handle to the peer, NULL on error
870 struct GNUNET_TESTING_Peer *
871 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
872 struct GNUNET_CONFIGURATION_Handle *cfg,
874 struct GNUNET_PeerIdentity *id,
877 struct GNUNET_TESTING_Peer *peer;
878 struct GNUNET_DISK_FileHandle *fd;
880 char hostkey_filename[128];
881 char *config_filename;
882 char *libexec_binary;
884 struct GNUNET_CRYPTO_EccPrivateKey *pk;
888 if (GNUNET_OK != GNUNET_TESTING_configuration_create (system, cfg))
890 GNUNET_asprintf (&emsg_,
891 _("Failed to create configuration for peer (not enough free ports?)\n"));
892 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
899 if (key_number >= system->total_hostkeys)
901 GNUNET_asprintf (&emsg_,
902 _("You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"),
903 (unsigned int) system->total_hostkeys);
904 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
913 (NULL == (pk = GNUNET_TESTING_hostkey_get (system, key_number, id))))
915 GNUNET_asprintf (&emsg_,
916 _("Failed to initialize hostkey for peer %u\n"),
917 (unsigned int) key_number);
918 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
926 GNUNET_CRYPTO_ecc_key_free (pk);
927 GNUNET_assert (GNUNET_OK ==
928 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
931 /* FIXME: might be better to evaluate actual configuration option here... */
932 GNUNET_snprintf (hostkey_filename, sizeof (hostkey_filename), "%s/private.ecc",
934 GNUNET_free (service_home);
935 fd = GNUNET_DISK_file_open (hostkey_filename,
936 GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
937 GNUNET_DISK_PERM_USER_READ
938 | GNUNET_DISK_PERM_USER_WRITE);
944 if (GNUNET_TESTING_HOSTKEYFILESIZE !=
945 GNUNET_DISK_file_write (fd, system->hostkeys_data
946 + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE),
947 GNUNET_TESTING_HOSTKEYFILESIZE))
949 GNUNET_asprintf (&emsg_,
950 _("Failed to write hostkey file for peer %u: %s\n"),
951 (unsigned int) key_number,
953 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
958 GNUNET_DISK_file_close (fd);
961 GNUNET_DISK_file_close (fd);
962 GNUNET_assert (GNUNET_OK ==
963 GNUNET_CONFIGURATION_get_value_string
964 (cfg, "PATHS", "DEFAULTCONFIG", &config_filename));
965 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
967 GNUNET_asprintf (&emsg_,
968 _("Failed to write configuration file `%s' for peer %u: %s\n"),
970 (unsigned int) key_number,
972 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
977 GNUNET_free (config_filename);
980 peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
981 peer->cfgfile = config_filename; /* Free in peer_destroy */
982 peer->cfg = GNUNET_CONFIGURATION_dup (cfg);
983 libexec_binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
984 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "arm", "PREFIX", &peer->main_binary))
987 GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
988 peer->args = strdup ("");
991 peer->args = strdup (libexec_binary);
992 peer->system = system;
993 peer->key_number = key_number;
994 GNUNET_free (libexec_binary);
1000 * Obtain the peer identity from a peer handle.
1002 * @param peer peer handle for which we want the peer's identity
1003 * @param id identifier for the daemon, will be set
1006 GNUNET_TESTING_peer_get_identity (struct GNUNET_TESTING_Peer *peer,
1007 struct GNUNET_PeerIdentity *id)
1009 if (NULL != peer->id)
1011 memcpy (id, peer->id, sizeof (struct GNUNET_PeerIdentity));
1014 peer->id = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
1015 GNUNET_CRYPTO_ecc_key_free (GNUNET_TESTING_hostkey_get (peer->system,
1018 memcpy (id, peer->id, sizeof (struct GNUNET_PeerIdentity));
1025 * @param peer peer to start
1026 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
1029 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
1031 if (NULL != peer->main_process)
1034 return GNUNET_SYSERR;
1036 GNUNET_assert (NULL != peer->cfgfile);
1037 peer->main_process = GNUNET_OS_start_process (PIPE_CONTROL,
1038 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
1046 if (NULL == peer->main_process)
1048 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1049 _("Failed to start `%s': %s\n"),
1052 return GNUNET_SYSERR;
1059 GNUNET_TESTING_peer_service_start (struct GNUNET_TESTING_Peer *peer,
1060 const char *service_name,
1061 GNUNET_ARM_ResultCallback cont,
1064 GNUNET_ARM_request_service_start (peer->ah,
1066 GNUNET_OS_INHERIT_STD_ALL,
1067 GNUNET_TIME_UNIT_MINUTES,
1074 void GNUNET_TESTING_peer_service_stop (struct GNUNET_TESTING_Peer *peer,
1075 const char *service_name,
1076 GNUNET_ARM_ResultCallback cont,
1079 GNUNET_ARM_request_service_stop (peer->ah, service_name,
1080 GNUNET_TIME_UNIT_MINUTES,
1085 arm_start_result_cb (void *cls,
1086 struct GNUNET_ARM_Handle *arm,
1087 enum GNUNET_ARM_RequestStatus rs,
1088 const char *service,
1089 enum GNUNET_ARM_Result result)
1091 struct GNUNET_TESTING_Peer *peer = cls;
1093 if ((GNUNET_ARM_REQUEST_SENT_OK != rs)
1094 || ! ((GNUNET_ARM_RESULT_STARTING == result)
1095 || (GNUNET_ARM_RESULT_IS_STARTING_ALREADY == result)
1096 || (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result)))
1098 peer->cb (peer->cb_cls, peer, GNUNET_NO);
1101 peer->cb (peer->cb_cls, peer, GNUNET_OK);
1105 * Function called whenever we connect to or disconnect from ARM.
1107 * @param cls closure
1108 * @param arm handle to the ARM connection
1109 * @param connected GNUNET_YES if connected, GNUNET_NO if disconnected,
1110 * GNUNET_SYSERR on error.
1113 conn_status (void *cls, struct GNUNET_ARM_Handle *arm,
1116 struct GNUNET_TESTING_Peer *peer = cls;
1118 peer->cb (peer->cb_cls, peer, connected);
1123 GNUNET_TESTING_peer_start2 (struct GNUNET_TESTING_Peer *peer,
1124 GNUNET_TESTING_PeerStartCallback cb,
1127 if (NULL != peer->ah)
1130 return GNUNET_SYSERR;
1132 GNUNET_assert (NULL != (peer->cb = cb));
1133 peer->cb_cls = cb_cls;
1134 peer->ah = GNUNET_ARM_connect (peer->cfg, &conn_status, peer);
1135 if (NULL == peer->ah)
1136 return GNUNET_SYSERR;
1137 //GNUNET_TESTING_peer_service_start (peer, "arm", &arm_start_result_cb, peer);
1138 GNUNET_TESTING_peer_service_start (peer, "arm", NULL, NULL);
1145 * Sends SIGTERM to the peer's main process
1147 * @param peer the handle to the peer
1148 * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1149 * or upon any error while sending SIGTERM
1152 GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer)
1154 if (NULL == peer->main_process)
1157 return GNUNET_SYSERR;
1159 return (0 == GNUNET_OS_process_kill (peer->main_process, SIGTERM)) ?
1160 GNUNET_OK : GNUNET_SYSERR;
1165 * Waits for a peer to terminate. The peer's main process will also be destroyed.
1167 * @param peer the handle to the peer
1168 * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1169 * or upon any error while waiting
1172 GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer)
1176 if (NULL == peer->main_process)
1179 return GNUNET_SYSERR;
1181 ret = GNUNET_OS_process_wait (peer->main_process);
1182 GNUNET_OS_process_destroy (peer->main_process);
1183 peer->main_process = NULL;
1191 * @param peer peer to stop
1192 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1195 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
1197 if (GNUNET_SYSERR == GNUNET_TESTING_peer_kill (peer))
1198 return GNUNET_SYSERR;
1199 if (GNUNET_SYSERR == GNUNET_TESTING_peer_wait (peer))
1200 return GNUNET_SYSERR;
1205 arm_stop_result_cb (void *cls,
1206 struct GNUNET_ARM_Handle *arm,
1207 enum GNUNET_ARM_RequestStatus rs,
1208 const char *service,
1209 enum GNUNET_ARM_Result result)
1211 struct GNUNET_TESTING_Peer *peer = cls;
1213 if ((GNUNET_ARM_REQUEST_SENT_OK != rs)
1214 || ! ((GNUNET_ARM_RESULT_STOPPED == result)
1215 || (GNUNET_ARM_RESULT_STOPPING == result)
1216 || (GNUNET_ARM_RESULT_IS_STOPPING_ALREADY == result)
1217 || (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result)))
1219 peer->cb (peer->cb_cls, peer, GNUNET_NO);
1222 peer->cb (peer->cb_cls, peer, GNUNET_OK);
1227 arm_service_monitor (void *cls,
1228 struct GNUNET_ARM_MonitorHandle *arm,
1229 const char *service,
1230 enum GNUNET_ARM_ServiceStatus status)
1232 struct GNUNET_TESTING_Peer *peer = cls;
1235 if (GNUNET_ARM_SERVICE_STOPPED != status)
1237 if (0 != strcasecmp (service, "arm"))
1239 peer->cb (peer->cb_cls, peer, GNUNET_OK);
1244 GNUNET_TESTING_peer_stop2 (struct GNUNET_TESTING_Peer *peer,
1245 GNUNET_TESTING_PeerStartCallback cb,
1248 if (NULL == peer->ah)
1249 return GNUNET_SYSERR;
1250 GNUNET_assert (NULL != (peer->cb = cb));
1251 peer->cb_cls = cb_cls;
1252 /* if (NULL == peer->mh) */
1253 /* peer->mh = GNUNET_ARM_monitor (peer->cfg, &arm_service_monitor, peer); */
1254 GNUNET_TESTING_peer_service_stop (peer, "arm", NULL, NULL);
1260 * Destroy the peer. Releases resources locked during peer configuration.
1261 * If the peer is still running, it will be stopped AND a warning will be
1262 * printed (users of the API should stop the peer explicitly first).
1264 * @param peer peer to destroy
1267 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
1269 if (NULL != peer->main_process)
1270 GNUNET_TESTING_peer_stop (peer);
1271 if (NULL != peer->mh)
1272 GNUNET_ARM_monitor_disconnect_and_free (peer->mh);
1273 if (NULL != peer->ah)
1274 GNUNET_ARM_disconnect_and_free (peer->ah);
1275 GNUNET_free (peer->cfgfile);
1276 GNUNET_CONFIGURATION_destroy (peer->cfg);
1277 GNUNET_free (peer->main_binary);
1278 GNUNET_free (peer->args);
1279 GNUNET_free_non_null (peer->id);
1285 * Start a single peer and run a test using the testing library.
1286 * Starts a peer using the given configuration and then invokes the
1287 * given callback. This function ALSO initializes the scheduler loop
1288 * and should thus be called directly from "main". The testcase
1289 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1291 * @param testdir only the directory name without any path. This is used for
1292 * all service homes; the directory will be created in a temporary
1293 * location depending on the underlying OS
1294 * @param cfgfilename name of the configuration file to use;
1295 * use NULL to only run with defaults
1296 * @param tm main function of the testcase
1297 * @param tm_cls closure for 'tm'
1298 * @return 0 on success, 1 on error
1301 GNUNET_TESTING_peer_run (const char *testdir,
1302 const char *cfgfilename,
1303 GNUNET_TESTING_TestMain tm,
1306 return GNUNET_TESTING_service_run (testdir, "arm",
1307 cfgfilename, tm, tm_cls);
1312 * Structure for holding service data
1314 struct ServiceContext
1317 * The configuration of the peer in which the service is run
1319 const struct GNUNET_CONFIGURATION_Handle *cfg;
1322 * Callback to signal service startup
1324 GNUNET_TESTING_TestMain tm;
1327 * The peer in which the service is run.
1329 struct GNUNET_TESTING_Peer *peer;
1332 * Closure for the above callback
1339 * Callback to be called when SCHEDULER has been started
1341 * @param cls the ServiceContext
1342 * @param tc the TaskContext
1345 service_run_main (void *cls,
1346 const struct GNUNET_SCHEDULER_TaskContext *tc)
1348 struct ServiceContext *sc = cls;
1350 sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1355 * Start a single service (no ARM, except of course if the given
1356 * service name is 'arm') and run a test using the testing library.
1357 * Starts a service using the given configuration and then invokes the
1358 * given callback. This function ALSO initializes the scheduler loop
1359 * and should thus be called directly from "main". The testcase
1360 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1362 * This function is useful if the testcase is for a single service
1363 * and if that service doesn't itself depend on other services.
1365 * @param testdir only the directory name without any path. This is used for
1366 * all service homes; the directory will be created in a temporary
1367 * location depending on the underlying OS
1368 * @param service_name name of the service to run
1369 * @param cfgfilename name of the configuration file to use;
1370 * use NULL to only run with defaults
1371 * @param tm main function of the testcase
1372 * @param tm_cls closure for 'tm'
1373 * @return 0 on success, 1 on error
1376 GNUNET_TESTING_service_run (const char *testdir,
1377 const char *service_name,
1378 const char *cfgfilename,
1379 GNUNET_TESTING_TestMain tm,
1382 struct ServiceContext sc;
1383 struct GNUNET_TESTING_System *system;
1384 struct GNUNET_TESTING_Peer *peer;
1385 struct GNUNET_CONFIGURATION_Handle *cfg;
1387 char *libexec_binary;
1389 GNUNET_log_setup (testdir, "WARNING", NULL);
1390 system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL);
1393 cfg = GNUNET_CONFIGURATION_create ();
1394 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1396 LOG (GNUNET_ERROR_TYPE_ERROR,
1397 _("Failed to load configuration from %s\n"), cfgfilename);
1398 GNUNET_CONFIGURATION_destroy (cfg);
1399 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1402 peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1405 GNUNET_CONFIGURATION_destroy (cfg);
1406 hostkeys_unload (system);
1407 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1410 GNUNET_free (peer->main_binary);
1411 GNUNET_free (peer->args);
1412 GNUNET_asprintf (&binary, "gnunet-service-%s", service_name);
1413 libexec_binary = GNUNET_OS_get_libexec_binary_path (binary);
1414 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, service_name, "PREFIX", &peer->main_binary))
1417 GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1418 peer->args = strdup ("");
1421 peer->args = strdup (libexec_binary);
1423 GNUNET_free (libexec_binary);
1424 GNUNET_free (binary);
1425 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1427 GNUNET_TESTING_peer_destroy (peer);
1428 GNUNET_CONFIGURATION_destroy (cfg);
1429 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1436 GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1437 if ((NULL != peer->main_process) &&
1438 (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1440 GNUNET_TESTING_peer_destroy (peer);
1441 GNUNET_CONFIGURATION_destroy (cfg);
1442 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1445 GNUNET_TESTING_peer_destroy (peer);
1446 GNUNET_CONFIGURATION_destroy (cfg);
1447 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1453 * Sometimes we use the binary name to determine which specific
1454 * test to run. In those cases, the string after the last "_"
1455 * in 'argv[0]' specifies a string that determines the configuration
1456 * file or plugin to use.
1458 * This function returns the respective substring, taking care
1459 * of issues such as binaries ending in '.exe' on W32.
1461 * @param argv0 the name of the binary
1462 * @return string between the last '_' and the '.exe' (or the end of the string),
1463 * NULL if argv0 has no '_'
1466 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1468 size_t slen = strlen (argv0) + 1;
1473 memcpy (sbuf, argv0, slen);
1474 ret = strrchr (sbuf, '_');
1477 ret++; /* skip underscore */
1478 dot = strchr (ret, '.');
1481 return GNUNET_strdup (ret);
1485 /* end of testing.c */