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 keynumber of this peer's hostkey
190 * Testing includes a number of pre-created hostkeys for faster peer
191 * startup. This function loads such keys into memory from a file.
193 * @param system the testing system handle
194 * @return GNUNET_OK on success; GNUNET_SYSERR on error
197 hostkeys_load (struct GNUNET_TESTING_System *system)
203 GNUNET_assert (NULL == system->hostkeys_data);
204 data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
205 GNUNET_asprintf (&filename, "%s/testing_hostkeys.ecc", data_dir);
206 GNUNET_free (data_dir);
208 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
210 LOG (GNUNET_ERROR_TYPE_ERROR,
211 _("Hostkeys file not found: %s\n"), filename);
212 GNUNET_free (filename);
213 return GNUNET_SYSERR;
215 /* Check hostkey file size, read entire thing into memory */
217 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
221 GNUNET_free (filename);
222 return GNUNET_SYSERR; /* File is empty */
224 if (0 != (fs % GNUNET_TESTING_HOSTKEYFILESIZE))
226 LOG (GNUNET_ERROR_TYPE_ERROR,
227 _("Incorrect hostkey file format: %s\n"), filename);
228 GNUNET_free (filename);
229 return GNUNET_SYSERR;
231 system->map_fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
232 GNUNET_DISK_PERM_NONE);
233 if (NULL == system->map_fd)
235 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename);
236 GNUNET_free (filename);
237 return GNUNET_SYSERR;
239 system->total_hostkeys = fs / GNUNET_TESTING_HOSTKEYFILESIZE;
240 system->hostkeys_data = GNUNET_DISK_file_map (system->map_fd,
242 GNUNET_DISK_MAP_TYPE_READ,
244 GNUNET_free (filename);
250 * Function to remove the loaded hostkeys
252 * @param system the testing system handle
255 hostkeys_unload (struct GNUNET_TESTING_System *system)
257 GNUNET_break (NULL != system->hostkeys_data);
258 system->hostkeys_data = NULL;
259 GNUNET_DISK_file_unmap (system->map);
261 GNUNET_DISK_file_close (system->map_fd);
262 system->map_fd = NULL;
263 system->hostkeys_data = NULL;
264 system->total_hostkeys = 0;
269 * Create a system handle. There must only be one system
270 * handle per operating system.
272 * @param testdir only the directory name without any path. This is used for
273 * all service homes; the directory will be created in a temporary
274 * location depending on the underlying OS
275 * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
276 * service configurations generated to allow control connections from
277 * this ip. This can either be a single ip address or a network address
279 * @param hostname the hostname of the system we are using for testing; NULL for
281 * @param lowport lowest port number this system is allowed to allocate (inclusive)
282 * @param highport highest port number this system is allowed to allocate (exclusive)
283 * @return handle to this system, NULL on error
285 struct GNUNET_TESTING_System *
286 GNUNET_TESTING_system_create_with_portrange (const char *testdir,
287 const char *trusted_ip,
288 const char *hostname,
292 struct GNUNET_TESTING_System *system;
294 GNUNET_assert (NULL != testdir);
295 system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
296 system->tmppath = GNUNET_DISK_mkdtemp (testdir);
297 system->lowport = lowport;
298 system->highport = highport;
299 if (NULL == system->tmppath)
301 GNUNET_free (system);
304 if (NULL != trusted_ip)
305 system->trusted_ip = GNUNET_strdup (trusted_ip);
306 if (NULL != hostname)
307 system->hostname = GNUNET_strdup (hostname);
308 if (GNUNET_OK != hostkeys_load (system))
310 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
318 * Create a system handle. There must only be one system handle per operating
319 * system. Uses a default range for allowed ports. Ports are still tested for
322 * @param testdir only the directory name without any path. This is used for all
323 * service homes; the directory will be created in a temporary location
324 * depending on the underlying OS
325 * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
326 * service configurations generated to allow control connections from
327 * this ip. This can either be a single ip address or a network address
329 * @param hostname the hostname of the system we are using for testing; NULL for
331 * @return handle to this system, NULL on error
333 struct GNUNET_TESTING_System *
334 GNUNET_TESTING_system_create (const char *testdir,
335 const char *trusted_ip,
336 const char *hostname)
338 return GNUNET_TESTING_system_create_with_portrange (testdir,
347 * Free system resources.
349 * @param system system to be freed
350 * @param remove_paths should the 'testdir' and all subdirectories
351 * be removed (clean up on shutdown)?
354 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
357 if (NULL != system->hostkeys_data)
358 hostkeys_unload (system);
359 if (GNUNET_YES == remove_paths)
360 GNUNET_DISK_directory_remove (system->tmppath);
361 GNUNET_free (system->tmppath);
362 GNUNET_free_non_null (system->trusted_ip);
363 GNUNET_free_non_null (system->hostname);
364 GNUNET_free (system);
369 * Reserve a TCP or UDP port for a peer.
371 * @param system system to use for reservation tracking
372 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
373 * @return 0 if no free port was available
376 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system,
379 struct GNUNET_NETWORK_Handle *socket;
380 struct addrinfo hint;
381 struct addrinfo *ret;
383 uint32_t *port_buckets;
392 FIXME: Instead of using getaddrinfo we should try to determine the port
393 status by the following heurestics.
395 On systems which support both IPv4 and IPv6, only ports open on both
396 address families are considered open.
397 On system with either IPv4 or IPv6. A port is considered open if it's
398 open in the respective address family
400 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
401 hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM;
402 hint.ai_protocol = 0;
405 hint.ai_canonname = NULL;
407 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
408 port_buckets = (GNUNET_YES == is_tcp) ?
409 system->reserved_tcp_ports : system->reserved_udp_ports;
410 for (index = (system->lowport / 32) + 1; index < (system->highport / 32); index++)
412 xor_image = (UINT32_MAX ^ port_buckets[index]);
413 if (0 == xor_image) /* Ports in the bucket are full */
415 pos = system->lowport % 32;
418 if (0 == ((xor_image >> pos) & 1U))
423 open_port = (index * 32) + pos;
424 if (open_port >= system->highport)
426 GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
428 GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
429 GNUNET_free (open_port_str);
430 bind_status = GNUNET_NO;
431 for (ai = ret; NULL != ai; ai = ai->ai_next)
433 socket = GNUNET_NETWORK_socket_create (ai->ai_family,
434 (GNUNET_YES == is_tcp) ?
435 SOCK_STREAM : SOCK_DGRAM,
439 bind_status = GNUNET_NETWORK_socket_bind (socket,
442 GNUNET_NETWORK_socket_close (socket);
443 if (GNUNET_OK != bind_status)
446 port_buckets[index] |= (1U << pos); /* Set the port bit */
448 if (GNUNET_OK == bind_status)
450 LOG (GNUNET_ERROR_TYPE_DEBUG,
451 "Found a free port %u\n", (unsigned int) open_port);
462 * Release reservation of a TCP or UDP port for a peer
463 * (used during GNUNET_TESTING_peer_destroy).
465 * @param system system to use for reservation tracking
466 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
467 * @param port reserved port to release
470 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
474 uint32_t *port_buckets;
478 port_buckets = (GNUNET_YES == is_tcp) ?
479 system->reserved_tcp_ports : system->reserved_udp_ports;
482 LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
483 if (0 == (port_buckets[bucket] & (1U << pos)))
485 GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
488 port_buckets[bucket] &= ~(1U << pos);
493 * Reserve a SERVICEHOME path for a peer.
495 * @param system system to use for reservation tracking
496 * @return NULL on error, otherwise fresh unique path to use
497 * as the servicehome for the peer; must be freed by the caller
501 reserve_path (struct GNUNET_TESTING_System *system)
505 GNUNET_asprintf (&reserved_path,
506 "%s/%u", system->tmppath, system->path_counter++);
507 return reserved_path;
512 * Testing includes a number of pre-created hostkeys for
513 * faster peer startup. This function can be used to
514 * access the n-th key of those pre-created hostkeys; note
515 * that these keys are ONLY useful for testing and not
516 * secure as the private keys are part of the public
517 * GNUnet source code.
519 * This is primarily a helper function used internally
520 * by 'GNUNET_TESTING_peer_configure'.
522 * @param system the testing system handle
523 * @param key_number desired pre-created hostkey to obtain
524 * @param id set to the peer's identity (hash of the public
525 * key; if NULL, GNUNET_SYSERR is returned immediately
526 * @return NULL on error (not enough keys)
528 struct GNUNET_CRYPTO_EccPrivateKey *
529 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
531 struct GNUNET_PeerIdentity *id)
533 struct GNUNET_CRYPTO_EccPrivateKey *private_key;
534 struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded public_key;
536 if ((NULL == id) || (NULL == system->hostkeys_data))
538 if (key_number >= system->total_hostkeys)
540 LOG (GNUNET_ERROR_TYPE_ERROR,
541 _("Key number %u does not exist\n"), key_number);
544 private_key = GNUNET_CRYPTO_ecc_decode_key (system->hostkeys_data +
546 GNUNET_TESTING_HOSTKEYFILESIZE),
547 GNUNET_TESTING_HOSTKEYFILESIZE);
548 if (NULL == private_key)
550 LOG (GNUNET_ERROR_TYPE_ERROR,
551 _("Error while decoding key %u\n"), key_number);
554 GNUNET_CRYPTO_ecc_key_get_public (private_key, &public_key);
555 GNUNET_CRYPTO_hash (&public_key,
556 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
563 * Structure for holding data to build new configurations from a configuration
569 * The system for which we are building configurations
571 struct GNUNET_TESTING_System *system;
574 * The configuration we are building
576 struct GNUNET_CONFIGURATION_Handle *cfg;
579 * The customized service home path for this peer
584 * build status - to signal error while building a configuration
591 * Function to iterate over options. Copies
592 * the options to the target configuration,
593 * updating PORT values as needed.
595 * @param cls the UpdateContext
596 * @param section name of the section
597 * @param option name of the option
598 * @param value value of the option
601 update_config (void *cls, const char *section, const char *option,
604 struct UpdateContext *uc = cls;
608 char *single_variable;
609 char *per_host_variable;
610 unsigned long long num_per_host;
613 if (GNUNET_OK != uc->status)
615 if (! ((0 == strcmp (option, "PORT"))
616 || (0 == strcmp (option, "UNIXPATH"))
617 || (0 == strcmp (option, "HOSTNAME"))))
619 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
620 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
621 if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
625 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
628 /* FIXME: What about UDP? */
629 new_port = GNUNET_TESTING_reserve_port (uc->system, GNUNET_YES);
632 uc->status = GNUNET_SYSERR;
633 GNUNET_free (single_variable);
634 GNUNET_free (per_host_variable);
637 GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
640 else if ((ival != 0) &&
642 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
644 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
648 /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
649 /* ival + ctx->fdnum % num_per_host); */
651 GNUNET_break (0); /* FIXME */
654 if (0 == strcmp (option, "UNIXPATH"))
657 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
660 GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock",
661 uc->service_home, section);
664 else if ((GNUNET_YES ==
665 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
670 GNUNET_break(0); /* FIXME */
673 if (0 == strcmp (option, "HOSTNAME"))
675 value = (NULL == uc->system->hostname) ? "localhost" : uc->system->hostname;
677 GNUNET_free (single_variable);
678 GNUNET_free (per_host_variable);
679 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
684 * Section iterator to set ACCEPT_FROM/ACCEPT_FROM6 to include the address of
685 * 'trusted_hosts' in all sections
687 * @param cls the UpdateContext
688 * @param section name of the section
691 update_config_sections (void *cls,
694 struct UpdateContext *uc = cls;
698 char *orig_allowed_hosts;
700 char *ACCEPT_FROM_key;
706 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
707 "TESTING_IGNORE_KEYS"))
711 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section,
712 "TESTING_IGNORE_KEYS", &val));
714 for (ikeys_cnt = 0; NULL != (ptr = strstr (ptr, ";")); ikeys_cnt++)
720 ikeys = GNUNET_malloc ((sizeof (char *)) * ikeys_cnt);
722 for (key = 0; key < ikeys_cnt; key++)
725 ptr = strstr (ptr, ";");
733 for (key = 0; key < ikeys_cnt; key++)
735 if (NULL != strstr (ikeys[key], "ADVERTISED_PORT"))
738 if ((key == ikeys_cnt) &&
739 (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
743 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "PORT", &ptr))
745 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section,
746 "ADVERTISED_PORT", ptr);
750 for (key = 0; key < ikeys_cnt; key++)
752 if (NULL != strstr (ikeys[key], "ACCEPT_FROM"))
761 GNUNET_free_non_null (val);
762 ACCEPT_FROM_key = "ACCEPT_FROM";
763 if ((NULL != uc->system->trusted_ip) &&
764 (NULL != strstr (uc->system->trusted_ip, ":"))) /* IPv6 in use */
765 ACCEPT_FROM_key = "ACCEPT_FROM6";
767 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, ACCEPT_FROM_key,
768 &orig_allowed_hosts))
770 orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
772 if (NULL == uc->system->trusted_ip)
773 allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
775 GNUNET_asprintf (&allowed_hosts, "%s%s;", orig_allowed_hosts,
776 uc->system->trusted_ip);
777 GNUNET_free (orig_allowed_hosts);
778 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, ACCEPT_FROM_key,
780 GNUNET_free (allowed_hosts);
785 * Create a new configuration using the given configuration as a template;
786 * ports and paths will be modified to select available ports on the local
787 * system. The default configuration will be available in PATHS section under
788 * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS
789 * section to the temporary directory specific to this configuration. If we run
790 * out of "*port" numbers, return SYSERR.
792 * This is primarily a helper function used internally
793 * by 'GNUNET_TESTING_peer_configure'.
795 * @param system system to use to coordinate resource usage
796 * @param cfg template configuration to update
797 * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
798 * be incomplete and should not be used there upon
801 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
802 struct GNUNET_CONFIGURATION_Handle *cfg)
804 struct UpdateContext uc;
805 char *default_config;
809 uc.status = GNUNET_OK;
810 GNUNET_asprintf (&uc.service_home, "%s/%u", system->tmppath,
811 system->path_counter++);
812 GNUNET_asprintf (&default_config, "%s/config", uc.service_home);
813 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
815 GNUNET_free (default_config);
816 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME",
818 /* make PORTs and UNIXPATHs unique */
819 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
820 /* allow connections to services from system trusted_ip host */
821 GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
822 /* enable loopback-based connections between peers */
823 GNUNET_CONFIGURATION_set_value_string (cfg,
825 "USE_LOCALADDR", "YES");
826 GNUNET_free (uc.service_home);
832 * Configure a GNUnet peer. GNUnet must be installed on the local
833 * system and available in the PATH.
835 * @param system system to use to coordinate resource usage
836 * @param cfg configuration to use; will be UPDATED (to reflect needed
837 * changes in port numbers and paths)
838 * @param key_number number of the hostkey to use for the peer
839 * @param id identifier for the daemon, will be set, can be NULL
840 * @param emsg set to freshly allocated error message (set to NULL on success),
842 * @return handle to the peer, NULL on error
844 struct GNUNET_TESTING_Peer *
845 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
846 struct GNUNET_CONFIGURATION_Handle *cfg,
848 struct GNUNET_PeerIdentity *id,
851 struct GNUNET_TESTING_Peer *peer;
852 struct GNUNET_DISK_FileHandle *fd;
854 char hostkey_filename[128];
855 char *config_filename;
856 char *libexec_binary;
858 struct GNUNET_CRYPTO_EccPrivateKey *pk;
862 if (GNUNET_OK != GNUNET_TESTING_configuration_create (system, cfg))
864 GNUNET_asprintf (&emsg_,
865 _("Failed to create configuration for peer (not enough free ports?)\n"));
866 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
873 if (key_number >= system->total_hostkeys)
875 GNUNET_asprintf (&emsg_,
876 _("You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"),
877 (unsigned int) system->total_hostkeys);
878 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
887 (NULL == (pk = GNUNET_TESTING_hostkey_get (system, key_number, id))))
889 GNUNET_asprintf (&emsg_,
890 _("Failed to initialize hostkey for peer %u\n"),
891 (unsigned int) key_number);
892 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
900 GNUNET_CRYPTO_ecc_key_free (pk);
901 GNUNET_assert (GNUNET_OK ==
902 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
905 /* FIXME: might be better to evaluate actual configuration option here... */
906 GNUNET_snprintf (hostkey_filename, sizeof (hostkey_filename), "%s/private.ecc",
908 GNUNET_free (service_home);
909 fd = GNUNET_DISK_file_open (hostkey_filename,
910 GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
911 GNUNET_DISK_PERM_USER_READ
912 | GNUNET_DISK_PERM_USER_WRITE);
918 if (GNUNET_TESTING_HOSTKEYFILESIZE !=
919 GNUNET_DISK_file_write (fd, system->hostkeys_data
920 + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE),
921 GNUNET_TESTING_HOSTKEYFILESIZE))
923 GNUNET_asprintf (&emsg_,
924 _("Failed to write hostkey file for peer %u: %s\n"),
925 (unsigned int) key_number,
927 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
932 GNUNET_DISK_file_close (fd);
935 GNUNET_DISK_file_close (fd);
936 GNUNET_assert (GNUNET_OK ==
937 GNUNET_CONFIGURATION_get_value_string
938 (cfg, "PATHS", "DEFAULTCONFIG", &config_filename));
939 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
941 GNUNET_asprintf (&emsg_,
942 _("Failed to write configuration file `%s' for peer %u: %s\n"),
944 (unsigned int) key_number,
946 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
951 GNUNET_free (config_filename);
954 peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
955 peer->cfgfile = config_filename; /* Free in peer_destroy */
956 libexec_binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
957 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "arm", "PREFIX", &peer->main_binary))
960 GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
961 peer->args = strdup ("");
964 peer->args = strdup (libexec_binary);
965 peer->system = system;
966 peer->key_number = key_number;
967 GNUNET_free (libexec_binary);
973 * Obtain the peer identity from a peer handle.
975 * @param peer peer handle for which we want the peer's identity
976 * @param id identifier for the daemon, will be set
979 GNUNET_TESTING_peer_get_identity (const struct GNUNET_TESTING_Peer *peer,
980 struct GNUNET_PeerIdentity *id)
982 GNUNET_CRYPTO_ecc_key_free (GNUNET_TESTING_hostkey_get (peer->system,
991 * @param peer peer to start
992 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
995 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
997 if (NULL != peer->main_process)
1000 return GNUNET_SYSERR;
1002 GNUNET_assert (NULL != peer->cfgfile);
1003 peer->main_process = GNUNET_OS_start_process (PIPE_CONTROL,
1004 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
1012 if (NULL == peer->main_process)
1014 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1015 _("Failed to start `%s': %s\n"),
1018 return GNUNET_SYSERR;
1025 * Sends SIGTERM to the peer's main process
1027 * @param peer the handle to the peer
1028 * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1029 * or upon any error while sending SIGTERM
1032 GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer)
1034 if (NULL == peer->main_process)
1037 return GNUNET_SYSERR;
1039 return (0 == GNUNET_OS_process_kill (peer->main_process, SIGTERM)) ?
1040 GNUNET_OK : GNUNET_SYSERR;
1045 * Waits for a peer to terminate. The peer's main process will also be destroyed.
1047 * @param peer the handle to the peer
1048 * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1049 * or upon any error while waiting
1052 GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer)
1056 if (NULL == peer->main_process)
1059 return GNUNET_SYSERR;
1061 ret = GNUNET_OS_process_wait (peer->main_process);
1062 GNUNET_OS_process_destroy (peer->main_process);
1063 peer->main_process = NULL;
1071 * @param peer peer to stop
1072 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1075 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
1077 if (GNUNET_SYSERR == GNUNET_TESTING_peer_kill (peer))
1078 return GNUNET_SYSERR;
1079 if (GNUNET_SYSERR == GNUNET_TESTING_peer_wait (peer))
1080 return GNUNET_SYSERR;
1086 * Destroy the peer. Releases resources locked during peer configuration.
1087 * If the peer is still running, it will be stopped AND a warning will be
1088 * printed (users of the API should stop the peer explicitly first).
1090 * @param peer peer to destroy
1093 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
1095 if (NULL != peer->main_process)
1098 GNUNET_TESTING_peer_stop (peer);
1100 GNUNET_free (peer->cfgfile);
1101 GNUNET_free (peer->main_binary);
1102 GNUNET_free (peer->args);
1108 * Start a single peer and run a test using the testing library.
1109 * Starts a peer using the given configuration and then invokes the
1110 * given callback. This function ALSO initializes the scheduler loop
1111 * and should thus be called directly from "main". The testcase
1112 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1114 * @param testdir only the directory name without any path. This is used for
1115 * all service homes; the directory will be created in a temporary
1116 * location depending on the underlying OS
1117 * @param cfgfilename name of the configuration file to use;
1118 * use NULL to only run with defaults
1119 * @param tm main function of the testcase
1120 * @param tm_cls closure for 'tm'
1121 * @return 0 on success, 1 on error
1124 GNUNET_TESTING_peer_run (const char *testdir,
1125 const char *cfgfilename,
1126 GNUNET_TESTING_TestMain tm,
1129 return GNUNET_TESTING_service_run (testdir, "arm",
1130 cfgfilename, tm, tm_cls);
1135 * Structure for holding service data
1137 struct ServiceContext
1140 * The configuration of the peer in which the service is run
1142 const struct GNUNET_CONFIGURATION_Handle *cfg;
1145 * Callback to signal service startup
1147 GNUNET_TESTING_TestMain tm;
1150 * The peer in which the service is run.
1152 struct GNUNET_TESTING_Peer *peer;
1155 * Closure for the above callback
1162 * Callback to be called when SCHEDULER has been started
1164 * @param cls the ServiceContext
1165 * @param tc the TaskContext
1168 service_run_main (void *cls,
1169 const struct GNUNET_SCHEDULER_TaskContext *tc)
1171 struct ServiceContext *sc = cls;
1173 sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1178 * Start a single service (no ARM, except of course if the given
1179 * service name is 'arm') and run a test using the testing library.
1180 * Starts a service using the given configuration and then invokes the
1181 * given callback. This function ALSO initializes the scheduler loop
1182 * and should thus be called directly from "main". The testcase
1183 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1185 * This function is useful if the testcase is for a single service
1186 * and if that service doesn't itself depend on other services.
1188 * @param testdir only the directory name without any path. This is used for
1189 * all service homes; the directory will be created in a temporary
1190 * location depending on the underlying OS
1191 * @param service_name name of the service to run
1192 * @param cfgfilename name of the configuration file to use;
1193 * use NULL to only run with defaults
1194 * @param tm main function of the testcase
1195 * @param tm_cls closure for 'tm'
1196 * @return 0 on success, 1 on error
1199 GNUNET_TESTING_service_run (const char *testdir,
1200 const char *service_name,
1201 const char *cfgfilename,
1202 GNUNET_TESTING_TestMain tm,
1205 struct ServiceContext sc;
1206 struct GNUNET_TESTING_System *system;
1207 struct GNUNET_TESTING_Peer *peer;
1208 struct GNUNET_CONFIGURATION_Handle *cfg;
1210 char *libexec_binary;
1212 GNUNET_log_setup (testdir, "WARNING", NULL);
1213 system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL);
1216 cfg = GNUNET_CONFIGURATION_create ();
1217 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1219 LOG (GNUNET_ERROR_TYPE_ERROR,
1220 _("Failed to load configuration from %s\n"), cfgfilename);
1221 GNUNET_CONFIGURATION_destroy (cfg);
1222 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1225 peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1228 GNUNET_CONFIGURATION_destroy (cfg);
1229 hostkeys_unload (system);
1230 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1233 GNUNET_free (peer->main_binary);
1234 GNUNET_free (peer->args);
1235 GNUNET_asprintf (&binary, "gnunet-service-%s", service_name);
1236 libexec_binary = GNUNET_OS_get_libexec_binary_path (binary);
1237 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, service_name, "PREFIX", &peer->main_binary))
1240 GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1241 peer->args = strdup ("");
1244 peer->args = strdup (libexec_binary);
1246 GNUNET_free (libexec_binary);
1247 GNUNET_free (binary);
1248 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1250 GNUNET_TESTING_peer_destroy (peer);
1251 GNUNET_CONFIGURATION_destroy (cfg);
1252 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1259 GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1260 if ((NULL != peer->main_process) &&
1261 (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1263 GNUNET_TESTING_peer_destroy (peer);
1264 GNUNET_CONFIGURATION_destroy (cfg);
1265 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1268 GNUNET_TESTING_peer_destroy (peer);
1269 GNUNET_CONFIGURATION_destroy (cfg);
1270 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1276 * Sometimes we use the binary name to determine which specific
1277 * test to run. In those cases, the string after the last "_"
1278 * in 'argv[0]' specifies a string that determines the configuration
1279 * file or plugin to use.
1281 * This function returns the respective substring, taking care
1282 * of issues such as binaries ending in '.exe' on W32.
1284 * @param argv0 the name of the binary
1285 * @return string between the last '_' and the '.exe' (or the end of the string),
1286 * NULL if argv0 has no '_'
1289 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1291 size_t slen = strlen (argv0) + 1;
1296 memcpy (sbuf, argv0, slen);
1297 ret = strrchr (sbuf, '_');
1300 ret++; /* skip underscore */
1301 dot = strchr (ret, '.');
1304 return GNUNET_strdup (ret);
1308 /* end of testing.c */