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_testing_lib.h"
36 #define LOG(kind,...) \
37 GNUNET_log_from (kind, "testing-api", __VA_ARGS__)
41 * We need pipe control only on WINDOWS
44 #define PIPE_CONTROL GNUNET_YES
46 #define PIPE_CONTROL GNUNET_NO
51 * Lowest port used for GNUnet testing. Should be high enough to not
52 * conflict with other applications running on the hosts but be low
53 * enough to not conflict with client-ports (typically starting around
56 #define LOW_PORT 12000
59 * Highest port used for GNUnet testing. Should be low enough to not
60 * conflict with the port range for "local" ports (client apps; see
61 * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
63 #define HIGH_PORT 56000
67 * Handle for a system on which GNUnet peers are executed;
68 * a system is used for reserving unique paths and ports.
70 struct GNUNET_TESTING_System
73 * Prefix (i.e. "/tmp/gnunet-testing/") we prepend to each
78 * The trusted ip. Can either be a single ip address or a network address in
89 * Hostkeys data, contains "GNUNET_TESTING_HOSTKEYFILESIZE * total_hostkeys" bytes.
94 * memory map for 'hostkeys_data'.
96 struct GNUNET_DISK_MapHandle *map;
99 * File descriptor for the map.
101 struct GNUNET_DISK_FileHandle *map_fd;
104 * Bitmap where each TCP port that has already been reserved for
105 * some GNUnet peer is recorded. Note that we additionally need to
106 * test if a port is already in use by non-GNUnet components before
107 * assigning it to a peer/service. If we detect that a port is
108 * already in use, we also mark it in this bitmap. So all the bits
109 * that are zero merely indicate ports that MIGHT be available for
112 uint32_t reserved_tcp_ports[65536 / 32];
115 * Bitmap where each UDP port that has already been reserved for
116 * some GNUnet peer is recorded. Note that we additionally need to
117 * test if a port is already in use by non-GNUnet components before
118 * assigning it to a peer/service. If we detect that a port is
119 * already in use, we also mark it in this bitmap. So all the bits
120 * that are zero merely indicate ports that MIGHT be available for
123 uint32_t reserved_udp_ports[65536 / 32];
126 * Counter we use to make service home paths unique on this system;
127 * the full path consists of the tmppath and this number. Each
128 * UNIXPATH for a peer is also modified to include the respective
129 * path counter to ensure uniqueness. This field is incremented
130 * by one for each configured peer. Even if peers are destroyed,
131 * we never re-use path counters.
133 uint32_t path_counter;
136 * The number of hostkeys
138 uint32_t total_hostkeys;
141 * Lowest port we are allowed to use.
146 * Highest port we are allowed to use.
153 * Handle for a GNUnet peer controlled by testing.
155 struct GNUNET_TESTING_Peer
158 * The TESTING system associated with this peer
160 struct GNUNET_TESTING_System *system;
163 * Path to the configuration file for this peer.
168 * Binary to be executed during 'GNUNET_TESTING_peer_start'.
169 * Typically 'gnunet-service-arm' (but can be set to a
170 * specific service by 'GNUNET_TESTING_service_run' if
177 * Handle to the running binary of the service, NULL if the
178 * peer/service is currently not running.
180 struct GNUNET_OS_Process *main_process;
183 * The cached identity of this peer. Will be populated on call to
184 * GNUNET_TESTING_peer_get_identity()
186 struct GNUNET_PeerIdentity *id;
189 * The keynumber of this peer's hostkey
196 * Testing includes a number of pre-created hostkeys for faster peer
197 * startup. This function loads such keys into memory from a file.
199 * @param system the testing system handle
200 * @return GNUNET_OK on success; GNUNET_SYSERR on error
203 hostkeys_load (struct GNUNET_TESTING_System *system)
209 GNUNET_assert (NULL == system->hostkeys_data);
210 data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
211 GNUNET_asprintf (&filename, "%s/testing_hostkeys.ecc", data_dir);
212 GNUNET_free (data_dir);
214 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
216 LOG (GNUNET_ERROR_TYPE_ERROR,
217 _("Hostkeys file not found: %s\n"), filename);
218 GNUNET_free (filename);
219 return GNUNET_SYSERR;
221 /* Check hostkey file size, read entire thing into memory */
223 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
227 GNUNET_free (filename);
228 return GNUNET_SYSERR; /* File is empty */
230 if (0 != (fs % GNUNET_TESTING_HOSTKEYFILESIZE))
232 LOG (GNUNET_ERROR_TYPE_ERROR,
233 _("Incorrect hostkey file format: %s\n"), filename);
234 GNUNET_free (filename);
235 return GNUNET_SYSERR;
237 system->map_fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
238 GNUNET_DISK_PERM_NONE);
239 if (NULL == system->map_fd)
241 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename);
242 GNUNET_free (filename);
243 return GNUNET_SYSERR;
245 system->total_hostkeys = fs / GNUNET_TESTING_HOSTKEYFILESIZE;
246 system->hostkeys_data = GNUNET_DISK_file_map (system->map_fd,
248 GNUNET_DISK_MAP_TYPE_READ,
250 GNUNET_free (filename);
256 * Function to remove the loaded hostkeys
258 * @param system the testing system handle
261 hostkeys_unload (struct GNUNET_TESTING_System *system)
263 GNUNET_break (NULL != system->hostkeys_data);
264 system->hostkeys_data = NULL;
265 GNUNET_DISK_file_unmap (system->map);
267 GNUNET_DISK_file_close (system->map_fd);
268 system->map_fd = NULL;
269 system->hostkeys_data = NULL;
270 system->total_hostkeys = 0;
275 * Create a system handle. There must only be one system
276 * handle per operating system.
278 * @param testdir only the directory name without any path. This is used for
279 * all service homes; the directory will be created in a temporary
280 * location depending on the underlying OS
281 * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
282 * service configurations generated to allow control connections from
283 * this ip. This can either be a single ip address or a network address
285 * @param hostname the hostname of the system we are using for testing; NULL for
287 * @param lowport lowest port number this system is allowed to allocate (inclusive)
288 * @param highport highest port number this system is allowed to allocate (exclusive)
289 * @return handle to this system, NULL on error
291 struct GNUNET_TESTING_System *
292 GNUNET_TESTING_system_create_with_portrange (const char *testdir,
293 const char *trusted_ip,
294 const char *hostname,
298 struct GNUNET_TESTING_System *system;
300 GNUNET_assert (NULL != testdir);
301 system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
302 system->tmppath = GNUNET_DISK_mkdtemp (testdir);
303 system->lowport = lowport;
304 system->highport = highport;
305 if (NULL == system->tmppath)
307 GNUNET_free (system);
310 if (NULL != trusted_ip)
311 system->trusted_ip = GNUNET_strdup (trusted_ip);
312 if (NULL != hostname)
313 system->hostname = GNUNET_strdup (hostname);
314 if (GNUNET_OK != hostkeys_load (system))
316 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
324 * Create a system handle. There must only be one system handle per operating
325 * system. Uses a default range for allowed ports. Ports are still tested for
328 * @param testdir only the directory name without any path. This is used for all
329 * service homes; the directory will be created in a temporary location
330 * depending on the underlying OS
331 * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
332 * service configurations generated to allow control connections from
333 * this ip. This can either be a single ip address or a network address
335 * @param hostname the hostname of the system we are using for testing; NULL for
337 * @return handle to this system, NULL on error
339 struct GNUNET_TESTING_System *
340 GNUNET_TESTING_system_create (const char *testdir,
341 const char *trusted_ip,
342 const char *hostname)
344 return GNUNET_TESTING_system_create_with_portrange (testdir,
353 * Free system resources.
355 * @param system system to be freed
356 * @param remove_paths should the 'testdir' and all subdirectories
357 * be removed (clean up on shutdown)?
360 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
363 if (NULL != system->hostkeys_data)
364 hostkeys_unload (system);
365 if (GNUNET_YES == remove_paths)
366 GNUNET_DISK_directory_remove (system->tmppath);
367 GNUNET_free (system->tmppath);
368 GNUNET_free_non_null (system->trusted_ip);
369 GNUNET_free_non_null (system->hostname);
370 GNUNET_free (system);
375 * Reserve a TCP or UDP port for a peer.
377 * @param system system to use for reservation tracking
378 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
379 * @return 0 if no free port was available
382 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system,
385 struct GNUNET_NETWORK_Handle *socket;
386 struct addrinfo hint;
387 struct addrinfo *ret;
389 uint32_t *port_buckets;
398 FIXME: Instead of using getaddrinfo we should try to determine the port
399 status by the following heurestics.
401 On systems which support both IPv4 and IPv6, only ports open on both
402 address families are considered open.
403 On system with either IPv4 or IPv6. A port is considered open if it's
404 open in the respective address family
406 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
407 hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM;
408 hint.ai_protocol = 0;
411 hint.ai_canonname = NULL;
413 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
414 port_buckets = (GNUNET_YES == is_tcp) ?
415 system->reserved_tcp_ports : system->reserved_udp_ports;
416 for (index = (system->lowport / 32) + 1; index < (system->highport / 32); index++)
418 xor_image = (UINT32_MAX ^ port_buckets[index]);
419 if (0 == xor_image) /* Ports in the bucket are full */
421 pos = system->lowport % 32;
424 if (0 == ((xor_image >> pos) & 1U))
429 open_port = (index * 32) + pos;
430 if (open_port >= system->highport)
432 GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
434 GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
435 GNUNET_free (open_port_str);
436 bind_status = GNUNET_NO;
437 for (ai = ret; NULL != ai; ai = ai->ai_next)
439 socket = GNUNET_NETWORK_socket_create (ai->ai_family,
440 (GNUNET_YES == is_tcp) ?
441 SOCK_STREAM : SOCK_DGRAM,
445 bind_status = GNUNET_NETWORK_socket_bind (socket,
448 GNUNET_NETWORK_socket_close (socket);
449 if (GNUNET_OK != bind_status)
452 port_buckets[index] |= (1U << pos); /* Set the port bit */
454 if (GNUNET_OK == bind_status)
456 LOG (GNUNET_ERROR_TYPE_DEBUG,
457 "Found a free port %u\n", (unsigned int) open_port);
468 * Release reservation of a TCP or UDP port for a peer
469 * (used during GNUNET_TESTING_peer_destroy).
471 * @param system system to use for reservation tracking
472 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
473 * @param port reserved port to release
476 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
480 uint32_t *port_buckets;
484 port_buckets = (GNUNET_YES == is_tcp) ?
485 system->reserved_tcp_ports : system->reserved_udp_ports;
488 LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
489 if (0 == (port_buckets[bucket] & (1U << pos)))
491 GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
494 port_buckets[bucket] &= ~(1U << pos);
499 * Reserve a SERVICEHOME path for a peer.
501 * @param system system to use for reservation tracking
502 * @return NULL on error, otherwise fresh unique path to use
503 * as the servicehome for the peer; must be freed by the caller
507 reserve_path (struct GNUNET_TESTING_System *system)
511 GNUNET_asprintf (&reserved_path,
512 "%s/%u", system->tmppath, system->path_counter++);
513 return reserved_path;
518 * Testing includes a number of pre-created hostkeys for
519 * faster peer startup. This function can be used to
520 * access the n-th key of those pre-created hostkeys; note
521 * that these keys are ONLY useful for testing and not
522 * secure as the private keys are part of the public
523 * GNUnet source code.
525 * This is primarily a helper function used internally
526 * by 'GNUNET_TESTING_peer_configure'.
528 * @param system the testing system handle
529 * @param key_number desired pre-created hostkey to obtain
530 * @param id set to the peer's identity (hash of the public
531 * key; if NULL, GNUNET_SYSERR is returned immediately
532 * @return NULL on error (not enough keys)
534 struct GNUNET_CRYPTO_EccPrivateKey *
535 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
537 struct GNUNET_PeerIdentity *id)
539 struct GNUNET_CRYPTO_EccPrivateKey *private_key;
540 struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded public_key;
542 if ((NULL == id) || (NULL == system->hostkeys_data))
544 if (key_number >= system->total_hostkeys)
546 LOG (GNUNET_ERROR_TYPE_ERROR,
547 _("Key number %u does not exist\n"), key_number);
550 private_key = GNUNET_CRYPTO_ecc_decode_key (system->hostkeys_data +
552 GNUNET_TESTING_HOSTKEYFILESIZE),
553 GNUNET_TESTING_HOSTKEYFILESIZE,
555 if (NULL == private_key)
557 LOG (GNUNET_ERROR_TYPE_ERROR,
558 _("Error while decoding key %u\n"), key_number);
561 GNUNET_CRYPTO_ecc_key_get_public (private_key, &public_key);
562 GNUNET_CRYPTO_hash (&public_key,
563 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
570 * Structure for holding data to build new configurations from a configuration
576 * The system for which we are building configurations
578 struct GNUNET_TESTING_System *system;
581 * The configuration we are building
583 struct GNUNET_CONFIGURATION_Handle *cfg;
586 * The customized service home path for this peer
591 * build status - to signal error while building a configuration
598 * Function to iterate over options. Copies
599 * the options to the target configuration,
600 * updating PORT values as needed.
602 * @param cls the UpdateContext
603 * @param section name of the section
604 * @param option name of the option
605 * @param value value of the option
608 update_config (void *cls, const char *section, const char *option,
611 struct UpdateContext *uc = cls;
615 char *single_variable;
616 char *per_host_variable;
617 unsigned long long num_per_host;
620 if (GNUNET_OK != uc->status)
622 if (! ((0 == strcmp (option, "PORT"))
623 || (0 == strcmp (option, "UNIXPATH"))
624 || (0 == strcmp (option, "HOSTNAME"))))
626 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
627 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
628 if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
632 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
635 /* FIXME: What about UDP? */
636 new_port = GNUNET_TESTING_reserve_port (uc->system, GNUNET_YES);
639 uc->status = GNUNET_SYSERR;
640 GNUNET_free (single_variable);
641 GNUNET_free (per_host_variable);
644 GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
647 else if ((ival != 0) &&
649 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
651 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
655 /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
656 /* ival + ctx->fdnum % num_per_host); */
658 GNUNET_break (0); /* FIXME */
661 if (0 == strcmp (option, "UNIXPATH"))
664 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
667 GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock",
668 uc->service_home, section);
671 else if ((GNUNET_YES ==
672 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
677 GNUNET_break(0); /* FIXME */
680 if (0 == strcmp (option, "HOSTNAME"))
682 value = (NULL == uc->system->hostname) ? "localhost" : uc->system->hostname;
684 GNUNET_free (single_variable);
685 GNUNET_free (per_host_variable);
686 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
691 * Section iterator to set ACCEPT_FROM/ACCEPT_FROM6 to include the address of
692 * 'trusted_hosts' in all sections
694 * @param cls the UpdateContext
695 * @param section name of the section
698 update_config_sections (void *cls,
701 struct UpdateContext *uc = cls;
705 char *orig_allowed_hosts;
707 char *ACCEPT_FROM_key;
713 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
714 "TESTING_IGNORE_KEYS"))
718 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section,
719 "TESTING_IGNORE_KEYS", &val));
721 for (ikeys_cnt = 0; NULL != (ptr = strstr (ptr, ";")); ikeys_cnt++)
727 ikeys = GNUNET_malloc ((sizeof (char *)) * ikeys_cnt);
729 for (key = 0; key < ikeys_cnt; key++)
732 ptr = strstr (ptr, ";");
740 for (key = 0; key < ikeys_cnt; key++)
742 if (NULL != strstr (ikeys[key], "ADVERTISED_PORT"))
745 if ((key == ikeys_cnt) &&
746 (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
750 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "PORT", &ptr))
752 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section,
753 "ADVERTISED_PORT", ptr);
757 for (key = 0; key < ikeys_cnt; key++)
759 if (NULL != strstr (ikeys[key], "ACCEPT_FROM"))
768 GNUNET_free_non_null (val);
769 ACCEPT_FROM_key = "ACCEPT_FROM";
770 if ((NULL != uc->system->trusted_ip) &&
771 (NULL != strstr (uc->system->trusted_ip, ":"))) /* IPv6 in use */
772 ACCEPT_FROM_key = "ACCEPT_FROM6";
774 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, ACCEPT_FROM_key,
775 &orig_allowed_hosts))
777 orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
779 if (NULL == uc->system->trusted_ip)
780 allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
782 GNUNET_asprintf (&allowed_hosts, "%s%s;", orig_allowed_hosts,
783 uc->system->trusted_ip);
784 GNUNET_free (orig_allowed_hosts);
785 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, ACCEPT_FROM_key,
787 GNUNET_free (allowed_hosts);
792 * Create a new configuration using the given configuration as a template;
793 * ports and paths will be modified to select available ports on the local
794 * system. The default configuration will be available in PATHS section under
795 * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS
796 * section to the temporary directory specific to this configuration. If we run
797 * out of "*port" numbers, return SYSERR.
799 * This is primarily a helper function used internally
800 * by 'GNUNET_TESTING_peer_configure'.
802 * @param system system to use to coordinate resource usage
803 * @param cfg template configuration to update
804 * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
805 * be incomplete and should not be used there upon
808 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
809 struct GNUNET_CONFIGURATION_Handle *cfg)
811 struct UpdateContext uc;
812 char *default_config;
816 uc.status = GNUNET_OK;
817 GNUNET_asprintf (&uc.service_home, "%s/%u", system->tmppath,
818 system->path_counter++);
819 GNUNET_asprintf (&default_config, "%s/config", uc.service_home);
820 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
822 GNUNET_free (default_config);
823 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME",
825 /* make PORTs and UNIXPATHs unique */
826 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
827 /* allow connections to services from system trusted_ip host */
828 GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
829 /* enable loopback-based connections between peers */
830 GNUNET_CONFIGURATION_set_value_string (cfg,
832 "USE_LOCALADDR", "YES");
833 GNUNET_free (uc.service_home);
839 * Configure a GNUnet peer. GNUnet must be installed on the local
840 * system and available in the PATH.
842 * @param system system to use to coordinate resource usage
843 * @param cfg configuration to use; will be UPDATED (to reflect needed
844 * changes in port numbers and paths)
845 * @param key_number number of the hostkey to use for the peer
846 * @param id identifier for the daemon, will be set, can be NULL
847 * @param emsg set to freshly allocated error message (set to NULL on success),
849 * @return handle to the peer, NULL on error
851 struct GNUNET_TESTING_Peer *
852 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
853 struct GNUNET_CONFIGURATION_Handle *cfg,
855 struct GNUNET_PeerIdentity *id,
858 struct GNUNET_TESTING_Peer *peer;
859 struct GNUNET_DISK_FileHandle *fd;
861 char hostkey_filename[128];
862 char *config_filename;
863 char *libexec_binary;
865 struct GNUNET_CRYPTO_EccPrivateKey *pk;
869 if (GNUNET_OK != GNUNET_TESTING_configuration_create (system, cfg))
871 GNUNET_asprintf (&emsg_,
872 _("Failed to create configuration for peer (not enough free ports?)\n"));
873 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
880 if (key_number >= system->total_hostkeys)
882 GNUNET_asprintf (&emsg_,
883 _("You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"),
884 (unsigned int) system->total_hostkeys);
885 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
894 (NULL == (pk = GNUNET_TESTING_hostkey_get (system, key_number, id))))
896 GNUNET_asprintf (&emsg_,
897 _("Failed to initialize hostkey for peer %u\n"),
898 (unsigned int) key_number);
899 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
907 GNUNET_CRYPTO_ecc_key_free (pk);
908 GNUNET_assert (GNUNET_OK ==
909 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
912 /* FIXME: might be better to evaluate actual configuration option here... */
913 GNUNET_snprintf (hostkey_filename, sizeof (hostkey_filename), "%s/private.ecc",
915 GNUNET_free (service_home);
916 fd = GNUNET_DISK_file_open (hostkey_filename,
917 GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
918 GNUNET_DISK_PERM_USER_READ
919 | GNUNET_DISK_PERM_USER_WRITE);
925 if (GNUNET_TESTING_HOSTKEYFILESIZE !=
926 GNUNET_DISK_file_write (fd, system->hostkeys_data
927 + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE),
928 GNUNET_TESTING_HOSTKEYFILESIZE))
930 GNUNET_asprintf (&emsg_,
931 _("Failed to write hostkey file for peer %u: %s\n"),
932 (unsigned int) key_number,
934 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
939 GNUNET_DISK_file_close (fd);
942 GNUNET_DISK_file_close (fd);
943 GNUNET_assert (GNUNET_OK ==
944 GNUNET_CONFIGURATION_get_value_string
945 (cfg, "PATHS", "DEFAULTCONFIG", &config_filename));
946 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
948 GNUNET_asprintf (&emsg_,
949 _("Failed to write configuration file `%s' for peer %u: %s\n"),
951 (unsigned int) key_number,
953 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
958 GNUNET_free (config_filename);
961 peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
962 peer->cfgfile = config_filename; /* Free in peer_destroy */
963 libexec_binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
964 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "arm", "PREFIX", &peer->main_binary))
967 GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
968 peer->args = strdup ("");
971 peer->args = strdup (libexec_binary);
972 peer->system = system;
973 peer->key_number = key_number;
974 GNUNET_free (libexec_binary);
980 * Obtain the peer identity from a peer handle.
982 * @param peer peer handle for which we want the peer's identity
983 * @param id identifier for the daemon, will be set
986 GNUNET_TESTING_peer_get_identity (struct GNUNET_TESTING_Peer *peer,
987 struct GNUNET_PeerIdentity *id)
989 if (NULL != peer->id)
991 memcpy (id, peer->id, sizeof (struct GNUNET_PeerIdentity));
994 peer->id = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
995 GNUNET_CRYPTO_ecc_key_free (GNUNET_TESTING_hostkey_get (peer->system,
998 memcpy (id, peer->id, sizeof (struct GNUNET_PeerIdentity));
1005 * @param peer peer to start
1006 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
1009 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
1011 if (NULL != peer->main_process)
1014 return GNUNET_SYSERR;
1016 GNUNET_assert (NULL != peer->cfgfile);
1017 peer->main_process = GNUNET_OS_start_process (PIPE_CONTROL,
1018 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
1026 if (NULL == peer->main_process)
1028 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1029 _("Failed to start `%s': %s\n"),
1032 return GNUNET_SYSERR;
1039 * Sends SIGTERM to the peer's main process
1041 * @param peer the handle to the peer
1042 * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1043 * or upon any error while sending SIGTERM
1046 GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer)
1048 if (NULL == peer->main_process)
1051 return GNUNET_SYSERR;
1053 return (0 == GNUNET_OS_process_kill (peer->main_process, SIGTERM)) ?
1054 GNUNET_OK : GNUNET_SYSERR;
1059 * Waits for a peer to terminate. The peer's main process will also be destroyed.
1061 * @param peer the handle to the peer
1062 * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1063 * or upon any error while waiting
1066 GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer)
1070 if (NULL == peer->main_process)
1073 return GNUNET_SYSERR;
1075 ret = GNUNET_OS_process_wait (peer->main_process);
1076 GNUNET_OS_process_destroy (peer->main_process);
1077 peer->main_process = NULL;
1085 * @param peer peer to stop
1086 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1089 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
1091 if (GNUNET_SYSERR == GNUNET_TESTING_peer_kill (peer))
1092 return GNUNET_SYSERR;
1093 if (GNUNET_SYSERR == GNUNET_TESTING_peer_wait (peer))
1094 return GNUNET_SYSERR;
1100 * Destroy the peer. Releases resources locked during peer configuration.
1101 * If the peer is still running, it will be stopped AND a warning will be
1102 * printed (users of the API should stop the peer explicitly first).
1104 * @param peer peer to destroy
1107 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
1109 if (NULL != peer->main_process)
1112 GNUNET_TESTING_peer_stop (peer);
1114 GNUNET_free (peer->cfgfile);
1115 GNUNET_free (peer->main_binary);
1116 GNUNET_free (peer->args);
1117 GNUNET_free_non_null (peer->id);
1123 * Start a single peer and run a test using the testing library.
1124 * Starts a peer using the given configuration and then invokes the
1125 * given callback. This function ALSO initializes the scheduler loop
1126 * and should thus be called directly from "main". The testcase
1127 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1129 * @param testdir only the directory name without any path. This is used for
1130 * all service homes; the directory will be created in a temporary
1131 * location depending on the underlying OS
1132 * @param cfgfilename name of the configuration file to use;
1133 * use NULL to only run with defaults
1134 * @param tm main function of the testcase
1135 * @param tm_cls closure for 'tm'
1136 * @return 0 on success, 1 on error
1139 GNUNET_TESTING_peer_run (const char *testdir,
1140 const char *cfgfilename,
1141 GNUNET_TESTING_TestMain tm,
1144 return GNUNET_TESTING_service_run (testdir, "arm",
1145 cfgfilename, tm, tm_cls);
1150 * Structure for holding service data
1152 struct ServiceContext
1155 * The configuration of the peer in which the service is run
1157 const struct GNUNET_CONFIGURATION_Handle *cfg;
1160 * Callback to signal service startup
1162 GNUNET_TESTING_TestMain tm;
1165 * The peer in which the service is run.
1167 struct GNUNET_TESTING_Peer *peer;
1170 * Closure for the above callback
1177 * Callback to be called when SCHEDULER has been started
1179 * @param cls the ServiceContext
1180 * @param tc the TaskContext
1183 service_run_main (void *cls,
1184 const struct GNUNET_SCHEDULER_TaskContext *tc)
1186 struct ServiceContext *sc = cls;
1188 sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1193 * Start a single service (no ARM, except of course if the given
1194 * service name is 'arm') and run a test using the testing library.
1195 * Starts a service using the given configuration and then invokes the
1196 * given callback. This function ALSO initializes the scheduler loop
1197 * and should thus be called directly from "main". The testcase
1198 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1200 * This function is useful if the testcase is for a single service
1201 * and if that service doesn't itself depend on other services.
1203 * @param testdir only the directory name without any path. This is used for
1204 * all service homes; the directory will be created in a temporary
1205 * location depending on the underlying OS
1206 * @param service_name name of the service to run
1207 * @param cfgfilename name of the configuration file to use;
1208 * use NULL to only run with defaults
1209 * @param tm main function of the testcase
1210 * @param tm_cls closure for 'tm'
1211 * @return 0 on success, 1 on error
1214 GNUNET_TESTING_service_run (const char *testdir,
1215 const char *service_name,
1216 const char *cfgfilename,
1217 GNUNET_TESTING_TestMain tm,
1220 struct ServiceContext sc;
1221 struct GNUNET_TESTING_System *system;
1222 struct GNUNET_TESTING_Peer *peer;
1223 struct GNUNET_CONFIGURATION_Handle *cfg;
1225 char *libexec_binary;
1227 GNUNET_log_setup (testdir, "WARNING", NULL);
1228 system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL);
1231 cfg = GNUNET_CONFIGURATION_create ();
1232 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1234 LOG (GNUNET_ERROR_TYPE_ERROR,
1235 _("Failed to load configuration from %s\n"), cfgfilename);
1236 GNUNET_CONFIGURATION_destroy (cfg);
1237 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1240 peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1243 GNUNET_CONFIGURATION_destroy (cfg);
1244 hostkeys_unload (system);
1245 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1248 GNUNET_free (peer->main_binary);
1249 GNUNET_free (peer->args);
1250 GNUNET_asprintf (&binary, "gnunet-service-%s", service_name);
1251 libexec_binary = GNUNET_OS_get_libexec_binary_path (binary);
1252 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, service_name, "PREFIX", &peer->main_binary))
1255 GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1256 peer->args = strdup ("");
1259 peer->args = strdup (libexec_binary);
1261 GNUNET_free (libexec_binary);
1262 GNUNET_free (binary);
1263 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1265 GNUNET_TESTING_peer_destroy (peer);
1266 GNUNET_CONFIGURATION_destroy (cfg);
1267 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1274 GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1275 if ((NULL != peer->main_process) &&
1276 (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1278 GNUNET_TESTING_peer_destroy (peer);
1279 GNUNET_CONFIGURATION_destroy (cfg);
1280 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1283 GNUNET_TESTING_peer_destroy (peer);
1284 GNUNET_CONFIGURATION_destroy (cfg);
1285 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1291 * Sometimes we use the binary name to determine which specific
1292 * test to run. In those cases, the string after the last "_"
1293 * in 'argv[0]' specifies a string that determines the configuration
1294 * file or plugin to use.
1296 * This function returns the respective substring, taking care
1297 * of issues such as binaries ending in '.exe' on W32.
1299 * @param argv0 the name of the binary
1300 * @return string between the last '_' and the '.exe' (or the end of the string),
1301 * NULL if argv0 has no '_'
1304 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1306 size_t slen = strlen (argv0) + 1;
1311 memcpy (sbuf, argv0, slen);
1312 ret = strrchr (sbuf, '_');
1315 ret++; /* skip underscore */
1316 dot = strchr (ret, '.');
1319 return GNUNET_strdup (ret);
1323 /* end of testing.c */