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-new.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 hostname of the controller
88 * Hostkeys data, contains "GNUNET_TESTING_HOSTKEYFILESIZE * total_hostkeys" bytes.
93 * memory map for 'hostkeys_data'.
95 struct GNUNET_DISK_MapHandle *map;
98 * File descriptor for the map.
100 struct GNUNET_DISK_FileHandle *map_fd;
103 * Bitmap where each TCP port that has already been reserved for
104 * some GNUnet peer is recorded. Note that we additionally need to
105 * test if a port is already in use by non-GNUnet components before
106 * assigning it to a peer/service. If we detect that a port is
107 * already in use, we also mark it in this bitmap. So all the bits
108 * that are zero merely indicate ports that MIGHT be available for
111 uint32_t reserved_tcp_ports[65536 / 32];
114 * Bitmap where each UDP port that has already been reserved for
115 * some GNUnet peer is recorded. Note that we additionally need to
116 * test if a port is already in use by non-GNUnet components before
117 * assigning it to a peer/service. If we detect that a port is
118 * already in use, we also mark it in this bitmap. So all the bits
119 * that are zero merely indicate ports that MIGHT be available for
122 uint32_t reserved_udp_ports[65536 / 32];
125 * Counter we use to make service home paths unique on this system;
126 * the full path consists of the tmppath and this number. Each
127 * UNIXPATH for a peer is also modified to include the respective
128 * path counter to ensure uniqueness. This field is incremented
129 * by one for each configured peer. Even if peers are destroyed,
130 * we never re-use path counters.
132 uint32_t path_counter;
135 * The number of hostkeys
137 uint32_t total_hostkeys;
140 * Lowest port we are allowed to use.
145 * Highest port we are allowed to use.
152 * Handle for a GNUnet peer controlled by testing.
154 struct GNUNET_TESTING_Peer
157 * The TESTING system associated with this peer
159 struct GNUNET_TESTING_System *system;
162 * Path to the configuration file for this peer.
167 * Binary to be executed during 'GNUNET_TESTING_peer_start'.
168 * Typically 'gnunet-service-arm' (but can be set to a
169 * specific service by 'GNUNET_TESTING_service_run' if
176 * Handle to the running binary of the service, NULL if the
177 * peer/service is currently not running.
179 struct GNUNET_OS_Process *main_process;
182 * The keynumber of this peer's hostkey
189 * Testing includes a number of pre-created hostkeys for faster peer
190 * startup. This function loads such keys into memory from a file.
192 * @param system the testing system handle
193 * @return GNUNET_OK on success; GNUNET_SYSERR on error
196 hostkeys_load (struct GNUNET_TESTING_System *system)
202 GNUNET_assert (NULL == system->hostkeys_data);
203 data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
204 GNUNET_asprintf (&filename, "%s/testing_hostkeys.dat", data_dir);
205 GNUNET_free (data_dir);
207 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
209 LOG (GNUNET_ERROR_TYPE_ERROR,
210 _("Hostkeys file not found: %s\n"), filename);
211 GNUNET_free (filename);
212 return GNUNET_SYSERR;
214 /* Check hostkey file size, read entire thing into memory */
216 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
220 GNUNET_free (filename);
221 return GNUNET_SYSERR; /* File is empty */
223 if (0 != (fs % GNUNET_TESTING_HOSTKEYFILESIZE))
225 LOG (GNUNET_ERROR_TYPE_ERROR,
226 _("Incorrect hostkey file format: %s\n"), filename);
227 GNUNET_free (filename);
228 return GNUNET_SYSERR;
230 system->map_fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
231 GNUNET_DISK_PERM_NONE);
232 if (NULL == system->map_fd)
234 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename);
235 GNUNET_free (filename);
236 return GNUNET_SYSERR;
238 system->total_hostkeys = fs / GNUNET_TESTING_HOSTKEYFILESIZE;
239 system->hostkeys_data = GNUNET_DISK_file_map (system->map_fd,
241 GNUNET_DISK_MAP_TYPE_READ,
243 GNUNET_free (filename);
249 * Function to remove the loaded hostkeys
251 * @param system the testing system handle
254 hostkeys_unload (struct GNUNET_TESTING_System *system)
256 GNUNET_break (NULL != system->hostkeys_data);
257 system->hostkeys_data = NULL;
258 GNUNET_DISK_file_unmap (system->map);
260 GNUNET_DISK_file_close (system->map_fd);
261 system->map_fd = NULL;
262 system->hostkeys_data = NULL;
263 system->total_hostkeys = 0;
268 * Create a system handle. There must only be one system
269 * handle per operating system.
271 * @param testdir only the directory name without any path. This is used for
272 * all service homes; the directory will be created in a temporary
273 * location depending on the underlying OS
274 * @param controller hostname of the controlling host,
275 * service configurations are modified to allow
276 * control connections from this host; can be NULL
277 * @param hostname the hostname of the system we are using for testing; NULL for
279 * @param lowport lowest port number this system is allowed to allocate (inclusive)
280 * @param highport highest port number this system is allowed to allocate (exclusive)
281 * @return handle to this system, NULL on error
283 struct GNUNET_TESTING_System *
284 GNUNET_TESTING_system_create_with_portrange (const char *testdir,
285 const char *controller,
286 const char *hostname,
290 struct GNUNET_TESTING_System *system;
292 GNUNET_assert (NULL != testdir);
293 system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
294 system->tmppath = GNUNET_DISK_mkdtemp (testdir);
295 system->lowport = lowport;
296 system->highport = highport;
297 if (NULL == system->tmppath)
299 GNUNET_free (system);
302 if (NULL != controller)
303 system->controller = GNUNET_strdup (controller);
304 if (NULL != hostname)
305 system->hostname = GNUNET_strdup (hostname);
306 if (GNUNET_OK != hostkeys_load (system))
308 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
316 * Create a system handle. There must only be one system handle per operating
317 * system. Uses a default range for allowed ports. Ports are still tested for
320 * @param testdir only the directory name without any path. This is used for all
321 * service homes; the directory will be created in a temporary location
322 * depending on the underlying OS
323 * @param controller hostname of the controlling host, service configurations
324 * are modified to allow control connections from this host; can be NULL
325 * @param hostname the hostname of the system we are using for testing; NULL for
327 * @return handle to this system, NULL on error
329 struct GNUNET_TESTING_System *
330 GNUNET_TESTING_system_create (const char *testdir,
331 const char *controller,
332 const char *hostname)
334 return GNUNET_TESTING_system_create_with_portrange (testdir,
343 * Free system resources.
345 * @param system system to be freed
346 * @param remove_paths should the 'testdir' and all subdirectories
347 * be removed (clean up on shutdown)?
350 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
353 if (NULL != system->hostkeys_data)
354 hostkeys_unload (system);
355 if (GNUNET_YES == remove_paths)
356 GNUNET_DISK_directory_remove (system->tmppath);
357 GNUNET_free (system->tmppath);
358 GNUNET_free_non_null (system->controller);
359 GNUNET_free_non_null (system->hostname);
360 GNUNET_free (system);
365 * Reserve a TCP or UDP port for a peer.
367 * @param system system to use for reservation tracking
368 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
369 * @return 0 if no free port was available
372 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system,
375 struct GNUNET_NETWORK_Handle *socket;
376 struct addrinfo hint;
377 struct addrinfo *ret;
379 uint32_t *port_buckets;
388 FIXME: Instead of using getaddrinfo we should try to determine the port
389 status by the following heurestics.
391 On systems which support both IPv4 and IPv6, only ports open on both
392 address families are considered open.
393 On system with either IPv4 or IPv6. A port is considered open if it's
394 open in the respective address family
396 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
397 hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM;
398 hint.ai_protocol = 0;
401 hint.ai_canonname = NULL;
403 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
404 port_buckets = (GNUNET_YES == is_tcp) ?
405 system->reserved_tcp_ports : system->reserved_udp_ports;
406 for (index = (system->lowport / 32) + 1; index < (system->highport / 32); index++)
408 xor_image = (UINT32_MAX ^ port_buckets[index]);
409 if (0 == xor_image) /* Ports in the bucket are full */
411 pos = system->lowport % 32;
414 if (0 == ((xor_image >> pos) & 1U))
419 open_port = (index * 32) + pos;
420 if (open_port >= system->highport)
422 GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
424 GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
425 GNUNET_free (open_port_str);
426 bind_status = GNUNET_NO;
427 for (ai = ret; NULL != ai; ai = ai->ai_next)
429 socket = GNUNET_NETWORK_socket_create (ai->ai_family,
430 (GNUNET_YES == is_tcp) ?
431 SOCK_STREAM : SOCK_DGRAM,
435 bind_status = GNUNET_NETWORK_socket_bind (socket,
438 GNUNET_NETWORK_socket_close (socket);
439 if (GNUNET_OK != bind_status)
442 port_buckets[index] |= (1U << pos); /* Set the port bit */
444 if (GNUNET_OK == bind_status)
446 LOG (GNUNET_ERROR_TYPE_DEBUG,
447 "Found a free port %u\n", (unsigned int) open_port);
458 * Release reservation of a TCP or UDP port for a peer
459 * (used during GNUNET_TESTING_peer_destroy).
461 * @param system system to use for reservation tracking
462 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
463 * @param port reserved port to release
466 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
470 uint32_t *port_buckets;
474 port_buckets = (GNUNET_YES == is_tcp) ?
475 system->reserved_tcp_ports : system->reserved_udp_ports;
478 LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
479 if (0 == (port_buckets[bucket] & (1U << pos)))
481 GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
484 port_buckets[bucket] &= ~(1U << pos);
489 * Reserve a SERVICEHOME path for a peer.
491 * @param system system to use for reservation tracking
492 * @return NULL on error, otherwise fresh unique path to use
493 * as the servicehome for the peer; must be freed by the caller
497 reserve_path (struct GNUNET_TESTING_System *system)
501 GNUNET_asprintf (&reserved_path,
502 "%s/%u", system->tmppath, system->path_counter++);
503 return reserved_path;
508 * Testing includes a number of pre-created hostkeys for
509 * faster peer startup. This function can be used to
510 * access the n-th key of those pre-created hostkeys; note
511 * that these keys are ONLY useful for testing and not
512 * secure as the private keys are part of the public
513 * GNUnet source code.
515 * This is primarily a helper function used internally
516 * by 'GNUNET_TESTING_peer_configure'.
518 * @param system the testing system handle
519 * @param key_number desired pre-created hostkey to obtain
520 * @param id set to the peer's identity (hash of the public
521 * key; if NULL, GNUNET_SYSERR is returned immediately
522 * @return NULL on error (not enough keys)
524 struct GNUNET_CRYPTO_RsaPrivateKey *
525 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
527 struct GNUNET_PeerIdentity *id)
529 struct GNUNET_CRYPTO_RsaPrivateKey *private_key;
530 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
532 if ((NULL == id) || (NULL == system->hostkeys_data))
534 if (key_number >= system->total_hostkeys)
536 LOG (GNUNET_ERROR_TYPE_ERROR,
537 _("Key number %u does not exist\n"), key_number);
540 private_key = GNUNET_CRYPTO_rsa_decode_key (system->hostkeys_data +
542 GNUNET_TESTING_HOSTKEYFILESIZE),
543 GNUNET_TESTING_HOSTKEYFILESIZE);
544 if (NULL == private_key)
546 LOG (GNUNET_ERROR_TYPE_ERROR,
547 _("Error while decoding key %u\n"), key_number);
550 GNUNET_CRYPTO_rsa_key_get_public (private_key, &public_key);
551 GNUNET_CRYPTO_hash (&public_key,
552 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
559 * Structure for holding data to build new configurations from a configuration
565 * The system for which we are building configurations
567 struct GNUNET_TESTING_System *system;
570 * The configuration we are building
572 struct GNUNET_CONFIGURATION_Handle *cfg;
575 * The customized service home path for this peer
580 * build status - to signal error while building a configuration
587 * Function to iterate over options. Copies
588 * the options to the target configuration,
589 * updating PORT values as needed.
591 * @param cls the UpdateContext
592 * @param section name of the section
593 * @param option name of the option
594 * @param value value of the option
597 update_config (void *cls, const char *section, const char *option,
600 struct UpdateContext *uc = cls;
604 char *single_variable;
605 char *per_host_variable;
606 unsigned long long num_per_host;
609 if (GNUNET_OK != uc->status)
611 if (! ((0 == strcmp (option, "PORT"))
612 || (0 == strcmp (option, "UNIXPATH"))
613 || (0 == strcmp (option, "HOSTNAME"))))
615 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
616 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
617 if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
621 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
624 /* FIXME: What about UDP? */
625 new_port = GNUNET_TESTING_reserve_port (uc->system, GNUNET_YES);
628 uc->status = GNUNET_SYSERR;
629 GNUNET_free (single_variable);
630 GNUNET_free (per_host_variable);
633 GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
636 else if ((ival != 0) &&
638 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
640 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
644 /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
645 /* ival + ctx->fdnum % num_per_host); */
647 GNUNET_break (0); /* FIXME */
650 if (0 == strcmp (option, "UNIXPATH"))
653 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
656 GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock",
657 uc->service_home, section);
660 else if ((GNUNET_YES ==
661 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
666 GNUNET_break(0); /* FIXME */
669 if (0 == strcmp (option, "HOSTNAME"))
671 value = (NULL == uc->system->hostname) ? "localhost" : uc->system->hostname;
673 GNUNET_free (single_variable);
674 GNUNET_free (per_host_variable);
675 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
680 * Section iterator to set ACCEPT_FROM/ACCEPT_FROM6 depending on the ip of the
681 * controller in all sections
683 * @param cls the UpdateContext
684 * @param section name of the section
687 update_config_sections (void *cls,
690 struct UpdateContext *uc = cls;
694 char *orig_allowed_hosts;
696 char *ACCEPT_FROM_key;
702 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
703 "TESTING_IGNORE_KEYS"))
707 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section,
708 "TESTING_IGNORE_KEYS", &val));
710 for (ikeys_cnt = 0; NULL != (ptr = strstr (ptr, ";")); ikeys_cnt++)
716 ikeys = GNUNET_malloc ((sizeof (char *)) * ikeys_cnt);
718 for (key = 0; key < ikeys_cnt; key++)
721 ptr = strstr (ptr, ";");
729 for (key = 0; key < ikeys_cnt; key++)
731 if (NULL != strstr (ikeys[key], "ADVERTISED_PORT"))
734 if ((key == ikeys_cnt) &&
735 (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
739 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "PORT", &ptr))
741 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section,
742 "ADVERTISED_PORT", ptr);
746 for (key = 0; key < ikeys_cnt; key++)
748 if (NULL != strstr (ikeys[key], "ACCEPT_FROM"))
757 GNUNET_free_non_null (val);
758 ACCEPT_FROM_key = "ACCEPT_FROM";
759 if ((NULL != uc->system->controller) &&
760 (NULL != strstr (uc->system->controller, ":"))) /* IPv6 in use */
761 ACCEPT_FROM_key = "ACCEPT_FROM6";
763 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, ACCEPT_FROM_key,
764 &orig_allowed_hosts))
766 orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
768 if (NULL == uc->system->controller)
769 allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
771 GNUNET_asprintf (&allowed_hosts, "%s%s;", orig_allowed_hosts,
772 uc->system->controller);
773 GNUNET_free (orig_allowed_hosts);
774 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, ACCEPT_FROM_key,
776 GNUNET_free (allowed_hosts);
781 * Create a new configuration using the given configuration as a template;
782 * ports and paths will be modified to select available ports on the local
783 * system. The default configuration will be available in PATHS section under
784 * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS
785 * section to the temporary directory specific to this configuration. If we run
786 * out of "*port" numbers, return SYSERR.
788 * This is primarily a helper function used internally
789 * by 'GNUNET_TESTING_peer_configure'.
791 * @param system system to use to coordinate resource usage
792 * @param cfg template configuration to update
793 * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
794 * be incomplete and should not be used there upon
797 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
798 struct GNUNET_CONFIGURATION_Handle *cfg)
800 struct UpdateContext uc;
801 char *default_config;
805 uc.status = GNUNET_OK;
806 GNUNET_asprintf (&uc.service_home, "%s/%u", system->tmppath,
807 system->path_counter++);
808 GNUNET_asprintf (&default_config, "%s/config", uc.service_home);
809 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
811 GNUNET_free (default_config);
812 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME",
814 /* make PORTs and UNIXPATHs unique */
815 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
816 /* allow connections to services from system controller host */
817 GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
818 /* enable loopback-based connections between peers */
819 GNUNET_CONFIGURATION_set_value_string (cfg,
821 "USE_LOCALADDR", "YES");
822 GNUNET_free (uc.service_home);
828 * Configure a GNUnet peer. GNUnet must be installed on the local
829 * system and available in the PATH.
831 * @param system system to use to coordinate resource usage
832 * @param cfg configuration to use; will be UPDATED (to reflect needed
833 * changes in port numbers and paths)
834 * @param key_number number of the hostkey to use for the peer
835 * @param id identifier for the daemon, will be set, can be NULL
836 * @param emsg set to freshly allocated error message (set to NULL on success),
838 * @return handle to the peer, NULL on error
840 struct GNUNET_TESTING_Peer *
841 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
842 struct GNUNET_CONFIGURATION_Handle *cfg,
844 struct GNUNET_PeerIdentity *id,
847 struct GNUNET_TESTING_Peer *peer;
848 struct GNUNET_DISK_FileHandle *fd;
850 char hostkey_filename[128];
851 char *config_filename;
852 char *libexec_binary;
854 struct GNUNET_CRYPTO_RsaPrivateKey *pk;
858 if (GNUNET_OK != GNUNET_TESTING_configuration_create (system, cfg))
860 GNUNET_asprintf (&emsg_,
861 _("Failed to create configuration for peer (not enough free ports?)\n"));
862 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
869 if (key_number >= system->total_hostkeys)
871 GNUNET_asprintf (&emsg_,
872 _("You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"),
873 (unsigned int) system->total_hostkeys);
874 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
883 (NULL == (pk = GNUNET_TESTING_hostkey_get (system, key_number, id))))
885 GNUNET_asprintf (&emsg_,
886 _("Failed to initialize hostkey for peer %u\n"),
887 (unsigned int) key_number);
888 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
896 GNUNET_CRYPTO_rsa_key_free (pk);
897 GNUNET_assert (GNUNET_OK ==
898 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
901 GNUNET_snprintf (hostkey_filename, sizeof (hostkey_filename), "%s/.hostkey",
903 GNUNET_free (service_home);
904 fd = GNUNET_DISK_file_open (hostkey_filename,
905 GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
906 GNUNET_DISK_PERM_USER_READ
907 | GNUNET_DISK_PERM_USER_WRITE);
913 if (GNUNET_TESTING_HOSTKEYFILESIZE !=
914 GNUNET_DISK_file_write (fd, system->hostkeys_data
915 + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE),
916 GNUNET_TESTING_HOSTKEYFILESIZE))
918 GNUNET_asprintf (&emsg_,
919 _("Failed to write hostkey file for peer %u: %s\n"),
920 (unsigned int) key_number,
922 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
927 GNUNET_DISK_file_close (fd);
930 GNUNET_DISK_file_close (fd);
931 GNUNET_assert (GNUNET_OK ==
932 GNUNET_CONFIGURATION_get_value_string
933 (cfg, "PATHS", "DEFAULTCONFIG", &config_filename));
934 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
936 GNUNET_asprintf (&emsg_,
937 _("Failed to write configuration file `%s' for peer %u: %s\n"),
939 (unsigned int) key_number,
941 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
946 GNUNET_free (config_filename);
949 peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
950 peer->cfgfile = config_filename; /* Free in peer_destroy */
951 libexec_binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
952 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "arm", "PREFIX", &peer->main_binary))
955 GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
956 peer->args = strdup ("");
959 peer->args = strdup (libexec_binary);
960 peer->system = system;
961 peer->key_number = key_number;
962 GNUNET_free (libexec_binary);
968 * Obtain the peer identity from a peer handle.
970 * @param peer peer handle for which we want the peer's identity
971 * @param id identifier for the daemon, will be set
974 GNUNET_TESTING_peer_get_identity (const struct GNUNET_TESTING_Peer *peer,
975 struct GNUNET_PeerIdentity *id)
977 GNUNET_CRYPTO_rsa_key_free (GNUNET_TESTING_hostkey_get (peer->system,
986 * @param peer peer to start
987 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
990 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
992 if (NULL != peer->main_process)
995 return GNUNET_SYSERR;
997 GNUNET_assert (NULL != peer->cfgfile);
998 peer->main_process = GNUNET_OS_start_process (PIPE_CONTROL,
999 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
1007 if (NULL == peer->main_process)
1009 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1010 _("Failed to start `%s': %s\n"),
1013 return GNUNET_SYSERR;
1020 * Sends SIGTERM to the peer's main process
1022 * @param peer the handle to the peer
1023 * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1024 * or upon any error while sending SIGTERM
1027 GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer)
1029 if (NULL == peer->main_process)
1032 return GNUNET_SYSERR;
1034 return (0 == GNUNET_OS_process_kill (peer->main_process, SIGTERM)) ?
1035 GNUNET_OK : GNUNET_SYSERR;
1040 * Waits for a peer to terminate. The peer's main process will also be destroyed.
1042 * @param peer the handle to the peer
1043 * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1044 * or upon any error while waiting
1047 GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer)
1051 if (NULL == peer->main_process)
1054 return GNUNET_SYSERR;
1056 ret = GNUNET_OS_process_wait (peer->main_process);
1057 GNUNET_OS_process_destroy (peer->main_process);
1058 peer->main_process = NULL;
1066 * @param peer peer to stop
1067 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1070 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
1072 if (GNUNET_SYSERR == GNUNET_TESTING_peer_kill (peer))
1073 return GNUNET_SYSERR;
1074 if (GNUNET_SYSERR == GNUNET_TESTING_peer_wait (peer))
1075 return GNUNET_SYSERR;
1081 * Destroy the peer. Releases resources locked during peer configuration.
1082 * If the peer is still running, it will be stopped AND a warning will be
1083 * printed (users of the API should stop the peer explicitly first).
1085 * @param peer peer to destroy
1088 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
1090 if (NULL != peer->main_process)
1093 GNUNET_TESTING_peer_stop (peer);
1095 GNUNET_free (peer->cfgfile);
1096 GNUNET_free (peer->main_binary);
1097 GNUNET_free (peer->args);
1103 * Start a single peer and run a test using the testing library.
1104 * Starts a peer using the given configuration and then invokes the
1105 * given callback. This function ALSO initializes the scheduler loop
1106 * and should thus be called directly from "main". The testcase
1107 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1109 * @param testdir only the directory name without any path. This is used for
1110 * all service homes; the directory will be created in a temporary
1111 * location depending on the underlying OS
1112 * @param cfgfilename name of the configuration file to use;
1113 * use NULL to only run with defaults
1114 * @param tm main function of the testcase
1115 * @param tm_cls closure for 'tm'
1116 * @return 0 on success, 1 on error
1119 GNUNET_TESTING_peer_run (const char *testdir,
1120 const char *cfgfilename,
1121 GNUNET_TESTING_TestMain tm,
1124 return GNUNET_TESTING_service_run (testdir, "arm",
1125 cfgfilename, tm, tm_cls);
1130 * Structure for holding service data
1132 struct ServiceContext
1135 * The configuration of the peer in which the service is run
1137 const struct GNUNET_CONFIGURATION_Handle *cfg;
1140 * Callback to signal service startup
1142 GNUNET_TESTING_TestMain tm;
1145 * The peer in which the service is run.
1147 struct GNUNET_TESTING_Peer *peer;
1150 * Closure for the above callback
1157 * Callback to be called when SCHEDULER has been started
1159 * @param cls the ServiceContext
1160 * @param tc the TaskContext
1163 service_run_main (void *cls,
1164 const struct GNUNET_SCHEDULER_TaskContext *tc)
1166 struct ServiceContext *sc = cls;
1168 sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1173 * Start a single service (no ARM, except of course if the given
1174 * service name is 'arm') and run a test using the testing library.
1175 * Starts a service using the given configuration and then invokes the
1176 * given callback. This function ALSO initializes the scheduler loop
1177 * and should thus be called directly from "main". The testcase
1178 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1180 * This function is useful if the testcase is for a single service
1181 * and if that service doesn't itself depend on other services.
1183 * @param testdir only the directory name without any path. This is used for
1184 * all service homes; the directory will be created in a temporary
1185 * location depending on the underlying OS
1186 * @param service_name name of the service to run
1187 * @param cfgfilename name of the configuration file to use;
1188 * use NULL to only run with defaults
1189 * @param tm main function of the testcase
1190 * @param tm_cls closure for 'tm'
1191 * @return 0 on success, 1 on error
1194 GNUNET_TESTING_service_run (const char *testdir,
1195 const char *service_name,
1196 const char *cfgfilename,
1197 GNUNET_TESTING_TestMain tm,
1200 struct ServiceContext sc;
1201 struct GNUNET_TESTING_System *system;
1202 struct GNUNET_TESTING_Peer *peer;
1203 struct GNUNET_CONFIGURATION_Handle *cfg;
1205 char *libexec_binary;
1207 GNUNET_log_setup (testdir, "WARNING", NULL);
1208 system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL);
1211 cfg = GNUNET_CONFIGURATION_create ();
1212 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1214 LOG (GNUNET_ERROR_TYPE_ERROR,
1215 _("Failed to load configuration from %s\n"), cfgfilename);
1216 GNUNET_CONFIGURATION_destroy (cfg);
1217 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1220 peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1223 GNUNET_CONFIGURATION_destroy (cfg);
1224 hostkeys_unload (system);
1225 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1228 GNUNET_free (peer->main_binary);
1229 GNUNET_free (peer->args);
1230 GNUNET_asprintf (&binary, "gnunet-service-%s", service_name);
1231 libexec_binary = GNUNET_OS_get_libexec_binary_path (binary);
1232 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, service_name, "PREFIX", &peer->main_binary))
1235 GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1236 peer->args = strdup ("");
1239 peer->args = strdup (libexec_binary);
1241 GNUNET_free (libexec_binary);
1242 GNUNET_free (binary);
1243 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1245 GNUNET_TESTING_peer_destroy (peer);
1246 GNUNET_CONFIGURATION_destroy (cfg);
1247 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1254 GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1255 if ((NULL != peer->main_process) &&
1256 (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1258 GNUNET_TESTING_peer_destroy (peer);
1259 GNUNET_CONFIGURATION_destroy (cfg);
1260 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1263 GNUNET_TESTING_peer_destroy (peer);
1264 GNUNET_CONFIGURATION_destroy (cfg);
1265 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1271 * Sometimes we use the binary name to determine which specific
1272 * test to run. In those cases, the string after the last "_"
1273 * in 'argv[0]' specifies a string that determines the configuration
1274 * file or plugin to use.
1276 * This function returns the respective substring, taking care
1277 * of issues such as binaries ending in '.exe' on W32.
1279 * @param argv0 the name of the binary
1280 * @return string between the last '_' and the '.exe' (or the end of the string),
1281 * NULL if argv0 has no '_'
1284 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1286 size_t slen = strlen (argv0) + 1;
1291 memcpy (sbuf, argv0, slen);
1292 ret = strrchr (sbuf, '_');
1295 ret++; /* skip underscore */
1296 dot = strchr (ret, '.');
1299 return GNUNET_strdup (ret);
1303 /* end of testing.c */