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__)
40 * Lowest port used for GNUnet testing. Should be high enough to not
41 * conflict with other applications running on the hosts but be low
42 * enough to not conflict with client-ports (typically starting around
45 #define LOW_PORT 12000
48 * Highest port used for GNUnet testing. Should be low enough to not
49 * conflict with the port range for "local" ports (client apps; see
50 * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
52 #define HIGH_PORT 56000
56 * Handle for a system on which GNUnet peers are executed;
57 * a system is used for reserving unique paths and ports.
59 struct GNUNET_TESTING_System
62 * Prefix (i.e. "/tmp/gnunet-testing/") we prepend to each
67 * The hostname of the controller
77 * Hostkeys data, contains "GNUNET_TESTING_HOSTKEYFILESIZE * total_hostkeys" bytes.
82 * memory map for 'hostkeys_data'.
84 struct GNUNET_DISK_MapHandle *map;
87 * File descriptor for the map.
89 struct GNUNET_DISK_FileHandle *map_fd;
92 * Bitmap where each TCP port that has already been reserved for
93 * some GNUnet peer is recorded. Note that we additionally need to
94 * test if a port is already in use by non-GNUnet components before
95 * assigning it to a peer/service. If we detect that a port is
96 * already in use, we also mark it in this bitmap. So all the bits
97 * that are zero merely indicate ports that MIGHT be available for
100 uint32_t reserved_tcp_ports[65536 / 32];
103 * Bitmap where each UDP 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_udp_ports[65536 / 32];
114 * Counter we use to make service home paths unique on this system;
115 * the full path consists of the tmppath and this number. Each
116 * UNIXPATH for a peer is also modified to include the respective
117 * path counter to ensure uniqueness. This field is incremented
118 * by one for each configured peer. Even if peers are destroyed,
119 * we never re-use path counters.
121 uint32_t path_counter;
124 * The number of hostkeys
126 uint32_t total_hostkeys;
129 * Lowest port we are allowed to use.
134 * Highest port we are allowed to use.
141 * Handle for a GNUnet peer controlled by testing.
143 struct GNUNET_TESTING_Peer
146 * The TESTING system associated with this peer
148 struct GNUNET_TESTING_System *system;
151 * Path to the configuration file for this peer.
156 * Binary to be executed during 'GNUNET_TESTING_peer_start'.
157 * Typically 'gnunet-service-arm' (but can be set to a
158 * specific service by 'GNUNET_TESTING_service_run' if
164 * Handle to the running binary of the service, NULL if the
165 * peer/service is currently not running.
167 struct GNUNET_OS_Process *main_process;
170 * The keynumber of this peer's hostkey
177 * Testing includes a number of pre-created hostkeys for faster peer
178 * startup. This function loads such keys into memory from a file.
180 * @param system the testing system handle
181 * @return GNUNET_OK on success; GNUNET_SYSERR on error
184 hostkeys_load (struct GNUNET_TESTING_System *system)
190 GNUNET_assert (NULL == system->hostkeys_data);
191 data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
192 GNUNET_asprintf (&filename, "%s/testing_hostkeys.dat", data_dir);
193 GNUNET_free (data_dir);
195 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
197 LOG (GNUNET_ERROR_TYPE_ERROR,
198 _("Hostkeys file not found: %s\n"), filename);
199 GNUNET_free (filename);
200 return GNUNET_SYSERR;
202 /* Check hostkey file size, read entire thing into memory */
204 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
208 GNUNET_free (filename);
209 return GNUNET_SYSERR; /* File is empty */
211 if (0 != (fs % GNUNET_TESTING_HOSTKEYFILESIZE))
213 LOG (GNUNET_ERROR_TYPE_ERROR,
214 _("Incorrect hostkey file format: %s\n"), filename);
215 GNUNET_free (filename);
216 return GNUNET_SYSERR;
218 system->map_fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
219 GNUNET_DISK_PERM_NONE);
220 if (NULL == system->map_fd)
222 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename);
223 GNUNET_free (filename);
224 return GNUNET_SYSERR;
226 system->total_hostkeys = fs / GNUNET_TESTING_HOSTKEYFILESIZE;
227 system->hostkeys_data = GNUNET_DISK_file_map (system->map_fd,
229 GNUNET_DISK_MAP_TYPE_READ,
231 GNUNET_free (filename);
237 * Function to remove the loaded hostkeys
239 * @param system the testing system handle
242 hostkeys_unload (struct GNUNET_TESTING_System *system)
244 GNUNET_break (NULL != system->hostkeys_data);
245 system->hostkeys_data = NULL;
246 GNUNET_DISK_file_unmap (system->map);
248 GNUNET_DISK_file_close (system->map_fd);
249 system->map_fd = NULL;
250 system->hostkeys_data = NULL;
251 system->total_hostkeys = 0;
256 * Create a system handle. There must only be one system
257 * handle per operating system.
259 * @param testdir only the directory name without any path. This is used for
260 * all service homes; the directory will be created in a temporary
261 * location depending on the underlying OS
262 * @param controller hostname of the controlling host,
263 * service configurations are modified to allow
264 * control connections from this host; can be NULL
265 * @param hostname the hostname of the system we are using for testing; NULL for
267 * @param lowport lowest port number this system is allowed to allocate (inclusive)
268 * @param highport highest port number this system is allowed to allocate (exclusive)
269 * @return handle to this system, NULL on error
271 struct GNUNET_TESTING_System *
272 GNUNET_TESTING_system_create_with_portrange (const char *testdir,
273 const char *controller,
274 const char *hostname,
278 struct GNUNET_TESTING_System *system;
280 GNUNET_assert (NULL != testdir);
281 system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
282 system->tmppath = GNUNET_DISK_mkdtemp (testdir);
283 system->lowport = lowport;
284 system->highport = highport;
285 if (NULL == system->tmppath)
287 GNUNET_free (system);
290 if (NULL != controller)
291 system->controller = GNUNET_strdup (controller);
292 if (NULL != hostname)
293 system->hostname = GNUNET_strdup (hostname);
294 if (GNUNET_OK != hostkeys_load (system))
296 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
304 * Create a system handle. There must only be one system handle per operating
305 * system. Uses a default range for allowed ports. Ports are still tested for
308 * @param testdir only the directory name without any path. This is used for all
309 * service homes; the directory will be created in a temporary location
310 * depending on the underlying OS
311 * @param controller hostname of the controlling host, service configurations
312 * are modified to allow control connections from this host; can be NULL
313 * @param hostname the hostname of the system we are using for testing; NULL for
315 * @return handle to this system, NULL on error
317 struct GNUNET_TESTING_System *
318 GNUNET_TESTING_system_create (const char *testdir,
319 const char *controller,
320 const char *hostname)
322 return GNUNET_TESTING_system_create_with_portrange (testdir,
331 * Free system resources.
333 * @param system system to be freed
334 * @param remove_paths should the 'testdir' and all subdirectories
335 * be removed (clean up on shutdown)?
338 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
341 if (NULL != system->hostkeys_data)
342 hostkeys_unload (system);
343 if (GNUNET_YES == remove_paths)
344 GNUNET_DISK_directory_remove (system->tmppath);
345 GNUNET_free (system->tmppath);
346 GNUNET_free_non_null (system->controller);
347 GNUNET_free_non_null (system->hostname);
348 GNUNET_free (system);
353 * Reserve a TCP or UDP port for a peer.
355 * @param system system to use for reservation tracking
356 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
357 * @return 0 if no free port was available
360 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system,
363 struct GNUNET_NETWORK_Handle *socket;
364 struct addrinfo hint;
365 struct addrinfo *ret;
367 uint32_t *port_buckets;
376 FIXME: Instead of using getaddrinfo we should try to determine the port
377 status by the following heurestics.
379 On systems which support both IPv4 and IPv6, only ports open on both
380 address families are considered open.
381 On system with either IPv4 or IPv6. A port is considered open if it's
382 open in the respective address family
384 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
385 hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM;
386 hint.ai_protocol = 0;
389 hint.ai_canonname = NULL;
391 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
392 port_buckets = (GNUNET_YES == is_tcp) ?
393 system->reserved_tcp_ports : system->reserved_udp_ports;
394 for (index = (system->lowport / 32) + 1; index < (system->highport / 32); index++)
396 xor_image = (UINT32_MAX ^ port_buckets[index]);
397 if (0 == xor_image) /* Ports in the bucket are full */
399 pos = system->lowport % 32;
402 if (0 == ((xor_image >> pos) & 1U))
407 open_port = (index * 32) + pos;
408 if (open_port >= system->highport)
410 GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
412 GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
413 GNUNET_free (open_port_str);
414 for (ai = ret; NULL != ai; ai = ai->ai_next)
416 socket = GNUNET_NETWORK_socket_create (ai->ai_family,
417 (GNUNET_YES == is_tcp) ?
418 SOCK_STREAM : SOCK_DGRAM,
422 bind_status = GNUNET_NO;
425 bind_status = GNUNET_NETWORK_socket_bind (socket,
428 GNUNET_NETWORK_socket_close (socket);
429 if (GNUNET_OK != bind_status)
432 port_buckets[index] |= (1U << pos); /* Set the port bit */
434 if (GNUNET_OK == bind_status)
436 LOG (GNUNET_ERROR_TYPE_DEBUG,
437 "Found a free port %u\n", (unsigned int) open_port);
448 * Release reservation of a TCP or UDP port for a peer
449 * (used during GNUNET_TESTING_peer_destroy).
451 * @param system system to use for reservation tracking
452 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
453 * @param port reserved port to release
456 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
460 uint32_t *port_buckets;
464 port_buckets = (GNUNET_YES == is_tcp) ?
465 system->reserved_tcp_ports : system->reserved_udp_ports;
468 LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
469 if (0 == (port_buckets[bucket] & (1U << pos)))
471 GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
474 port_buckets[bucket] &= ~(1U << pos);
479 * Reserve a SERVICEHOME path for a peer.
481 * @param system system to use for reservation tracking
482 * @return NULL on error, otherwise fresh unique path to use
483 * as the servicehome for the peer; must be freed by the caller
487 reserve_path (struct GNUNET_TESTING_System *system)
491 GNUNET_asprintf (&reserved_path,
492 "%s/%u", system->tmppath, system->path_counter++);
493 return reserved_path;
498 * Testing includes a number of pre-created hostkeys for
499 * faster peer startup. This function can be used to
500 * access the n-th key of those pre-created hostkeys; note
501 * that these keys are ONLY useful for testing and not
502 * secure as the private keys are part of the public
503 * GNUnet source code.
505 * This is primarily a helper function used internally
506 * by 'GNUNET_TESTING_peer_configure'.
508 * @param system the testing system handle
509 * @param key_number desired pre-created hostkey to obtain
510 * @param id set to the peer's identity (hash of the public
511 * key; if NULL, GNUNET_SYSERR is returned immediately
512 * @return NULL on error (not enough keys)
514 struct GNUNET_CRYPTO_RsaPrivateKey *
515 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
517 struct GNUNET_PeerIdentity *id)
519 struct GNUNET_CRYPTO_RsaPrivateKey *private_key;
520 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
522 if ((NULL == id) || (NULL == system->hostkeys_data))
524 if (key_number >= system->total_hostkeys)
526 LOG (GNUNET_ERROR_TYPE_ERROR,
527 _("Key number %u does not exist\n"), key_number);
530 private_key = GNUNET_CRYPTO_rsa_decode_key (system->hostkeys_data +
532 GNUNET_TESTING_HOSTKEYFILESIZE),
533 GNUNET_TESTING_HOSTKEYFILESIZE);
534 if (NULL == private_key)
536 LOG (GNUNET_ERROR_TYPE_ERROR,
537 _("Error while decoding key %u\n"), key_number);
540 GNUNET_CRYPTO_rsa_key_get_public (private_key, &public_key);
541 GNUNET_CRYPTO_hash (&public_key,
542 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
549 * Structure for holding data to build new configurations from a configuration
555 * The system for which we are building configurations
557 struct GNUNET_TESTING_System *system;
560 * The configuration we are building
562 struct GNUNET_CONFIGURATION_Handle *cfg;
565 * The customized service home path for this peer
570 * build status - to signal error while building a configuration
577 * Function to iterate over options. Copies
578 * the options to the target configuration,
579 * updating PORT values as needed.
581 * @param cls the UpdateContext
582 * @param section name of the section
583 * @param option name of the option
584 * @param value value of the option
587 update_config (void *cls, const char *section, const char *option,
590 struct UpdateContext *uc = cls;
594 char *single_variable;
595 char *per_host_variable;
596 unsigned long long num_per_host;
599 if (GNUNET_OK != uc->status)
601 if (! ((0 == strcmp (option, "PORT"))
602 || (0 == strcmp (option, "UNIXPATH"))
603 || (0 == strcmp (option, "HOSTNAME"))))
605 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
606 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
607 if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
611 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
614 /* FIXME: What about UDP? */
615 new_port = GNUNET_TESTING_reserve_port (uc->system, GNUNET_YES);
618 uc->status = GNUNET_SYSERR;
621 GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
624 else if ((ival != 0) &&
626 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
628 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
632 /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
633 /* ival + ctx->fdnum % num_per_host); */
635 GNUNET_break (0); /* FIXME */
638 if (0 == strcmp (option, "UNIXPATH"))
641 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
644 GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock",
645 uc->service_home, section);
648 else if ((GNUNET_YES ==
649 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
654 GNUNET_break(0); /* FIXME */
657 if (0 == strcmp (option, "HOSTNAME"))
659 value = (NULL == uc->system->hostname) ? "localhost" : uc->system->hostname;
661 GNUNET_free (single_variable);
662 GNUNET_free (per_host_variable);
663 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
668 * Section iterator to set ACCEPT_FROM/ACCEPT_FROM6 depending on the ip of the
669 * controller in all sections
671 * @param cls the UpdateContext
672 * @param section name of the section
675 update_config_sections (void *cls,
678 struct UpdateContext *uc = cls;
682 char *orig_allowed_hosts;
684 char *ACCEPT_FROM_key;
690 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
691 "TESTING_IGNORE_KEYS"))
695 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section,
696 "TESTING_IGNORE_KEYS", &val));
698 for (ikeys_cnt = 0; NULL != (ptr = strstr (ptr, ";")); ikeys_cnt++)
704 ikeys = GNUNET_malloc ((sizeof (char *)) * ikeys_cnt);
706 for (key = 0; key < ikeys_cnt; key++)
709 ptr = strstr (ptr, ";");
717 for (key = 0; key < ikeys_cnt; key++)
719 if (NULL != strstr (ikeys[key], "ADVERTISED_PORT"))
722 if ((key == ikeys_cnt) &&
723 (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
727 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "PORT", &ptr))
729 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section,
730 "ADVERTISED_PORT", ptr);
734 for (key = 0; key < ikeys_cnt; key++)
736 if (NULL != strstr (ikeys[key], "ACCEPT_FROM"))
745 GNUNET_free_non_null (val);
746 ACCEPT_FROM_key = "ACCEPT_FROM";
747 if ((NULL != uc->system->controller) &&
748 (NULL != strstr (uc->system->controller, ":"))) /* IPv6 in use */
749 ACCEPT_FROM_key = "ACCEPT_FROM6";
751 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, ACCEPT_FROM_key,
752 &orig_allowed_hosts))
754 orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
756 if (NULL == uc->system->controller)
757 allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
759 GNUNET_asprintf (&allowed_hosts, "%s%s;", orig_allowed_hosts,
760 uc->system->controller);
761 GNUNET_free (orig_allowed_hosts);
762 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, ACCEPT_FROM_key,
764 GNUNET_free (allowed_hosts);
769 * Create a new configuration using the given configuration as a template;
770 * ports and paths will be modified to select available ports on the local
771 * system. The default configuration will be available in PATHS section under
772 * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS
773 * section to the temporary directory specific to this configuration. If we run
774 * out of "*port" numbers, return SYSERR.
776 * This is primarily a helper function used internally
777 * by 'GNUNET_TESTING_peer_configure'.
779 * @param system system to use to coordinate resource usage
780 * @param cfg template configuration to update
781 * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
782 * be incomplete and should not be used there upon
785 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
786 struct GNUNET_CONFIGURATION_Handle *cfg)
788 struct UpdateContext uc;
789 char *default_config;
793 uc.status = GNUNET_OK;
794 GNUNET_asprintf (&uc.service_home, "%s/%u", system->tmppath,
795 system->path_counter++);
796 GNUNET_asprintf (&default_config, "%s/config", uc.service_home);
797 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
799 GNUNET_free (default_config);
800 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME",
802 /* make PORTs and UNIXPATHs unique */
803 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
804 /* allow connections to services from system controller host */
805 GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
806 /* enable loopback-based connections between peers */
807 GNUNET_CONFIGURATION_set_value_string (cfg,
809 "USE_LOCALADDR", "YES");
810 GNUNET_free (uc.service_home);
816 * Configure a GNUnet peer. GNUnet must be installed on the local
817 * system and available in the PATH.
819 * @param system system to use to coordinate resource usage
820 * @param cfg configuration to use; will be UPDATED (to reflect needed
821 * changes in port numbers and paths)
822 * @param key_number number of the hostkey to use for the peer
823 * @param id identifier for the daemon, will be set, can be NULL
824 * @param emsg set to freshly allocated error message (set to NULL on success),
826 * @return handle to the peer, NULL on error
828 struct GNUNET_TESTING_Peer *
829 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
830 struct GNUNET_CONFIGURATION_Handle *cfg,
832 struct GNUNET_PeerIdentity *id,
835 struct GNUNET_TESTING_Peer *peer;
836 struct GNUNET_DISK_FileHandle *fd;
838 char hostkey_filename[128];
839 char *config_filename;
841 struct GNUNET_CRYPTO_RsaPrivateKey *pk;
845 if (GNUNET_OK != GNUNET_TESTING_configuration_create (system, cfg))
847 GNUNET_asprintf (&emsg_,
848 _("Failed to create configuration for peer (not enough free ports?)\n"));
849 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
856 if (key_number >= system->total_hostkeys)
858 GNUNET_asprintf (&emsg_,
859 _("You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"),
860 (unsigned int) system->total_hostkeys);
861 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
870 (NULL == (pk = GNUNET_TESTING_hostkey_get (system, key_number, id))))
872 GNUNET_asprintf (&emsg_,
873 _("Failed to initialize hostkey for peer %u\n"),
874 (unsigned int) key_number);
875 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
883 GNUNET_CRYPTO_rsa_key_free (pk);
884 GNUNET_assert (GNUNET_OK ==
885 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
888 GNUNET_snprintf (hostkey_filename, sizeof (hostkey_filename), "%s/.hostkey",
890 GNUNET_free (service_home);
891 fd = GNUNET_DISK_file_open (hostkey_filename,
892 GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
893 GNUNET_DISK_PERM_USER_READ
894 | GNUNET_DISK_PERM_USER_WRITE);
900 if (GNUNET_TESTING_HOSTKEYFILESIZE !=
901 GNUNET_DISK_file_write (fd, system->hostkeys_data
902 + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE),
903 GNUNET_TESTING_HOSTKEYFILESIZE))
905 GNUNET_asprintf (&emsg_,
906 _("Failed to write hostkey file for peer %u: %s\n"),
907 (unsigned int) key_number,
909 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
914 GNUNET_DISK_file_close (fd);
917 GNUNET_DISK_file_close (fd);
918 GNUNET_assert (GNUNET_OK ==
919 GNUNET_CONFIGURATION_get_value_string
920 (cfg, "PATHS", "DEFAULTCONFIG", &config_filename));
921 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
923 GNUNET_asprintf (&emsg_,
924 _("Failed to write configuration file `%s' for peer %u: %s\n"),
926 (unsigned int) key_number,
928 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
933 GNUNET_free (config_filename);
936 peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
937 peer->cfgfile = config_filename; /* Free in peer_destroy */
938 peer->main_binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
939 peer->system = system;
940 peer->key_number = key_number;
946 * Obtain the peer identity from a peer handle.
948 * @param peer peer handle for which we want the peer's identity
949 * @param id identifier for the daemon, will be set
952 GNUNET_TESTING_peer_get_identity (const struct GNUNET_TESTING_Peer *peer,
953 struct GNUNET_PeerIdentity *id)
955 GNUNET_CRYPTO_rsa_key_free (GNUNET_TESTING_hostkey_get (peer->system,
964 * @param peer peer to start
965 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
968 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
970 if (NULL != peer->main_process)
973 return GNUNET_SYSERR;
975 GNUNET_assert (NULL != peer->cfgfile);
976 peer->main_process = GNUNET_OS_start_process (GNUNET_YES, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL,
982 if (NULL == peer->main_process)
984 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
985 _("Failed to start `%s': %s\n"),
988 return GNUNET_SYSERR;
990 return GNUNET_OS_set_process_priority (peer->main_process, GNUNET_SCHEDULER_PRIORITY_BACKGROUND);
997 * @param peer peer to stop
998 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer not running)
1001 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
1003 if (NULL == peer->main_process)
1006 return GNUNET_SYSERR;
1008 (void) GNUNET_OS_process_kill (peer->main_process, SIGTERM);
1009 GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (peer->main_process));
1010 GNUNET_OS_process_destroy (peer->main_process);
1011 peer->main_process = NULL;
1017 * Destroy the peer. Releases resources locked during peer configuration.
1018 * If the peer is still running, it will be stopped AND a warning will be
1019 * printed (users of the API should stop the peer explicitly first).
1021 * @param peer peer to destroy
1024 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
1026 if (NULL != peer->main_process)
1029 GNUNET_TESTING_peer_stop (peer);
1031 GNUNET_free (peer->cfgfile);
1032 GNUNET_free (peer->main_binary);
1038 * Start a single peer and run a test using the testing library.
1039 * Starts a peer using the given configuration and then invokes the
1040 * given callback. This function ALSO initializes the scheduler loop
1041 * and should thus be called directly from "main". The testcase
1042 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1044 * @param testdir only the directory name without any path. This is used for
1045 * all service homes; the directory will be created in a temporary
1046 * location depending on the underlying OS
1047 * @param cfgfilename name of the configuration file to use;
1048 * use NULL to only run with defaults
1049 * @param tm main function of the testcase
1050 * @param tm_cls closure for 'tm'
1051 * @return 0 on success, 1 on error
1054 GNUNET_TESTING_peer_run (const char *testdir,
1055 const char *cfgfilename,
1056 GNUNET_TESTING_TestMain tm,
1059 return GNUNET_TESTING_service_run (testdir, "arm",
1060 cfgfilename, tm, tm_cls);
1065 * Structure for holding service data
1067 struct ServiceContext
1070 * The configuration of the peer in which the service is run
1072 const struct GNUNET_CONFIGURATION_Handle *cfg;
1075 * Callback to signal service startup
1077 GNUNET_TESTING_TestMain tm;
1080 * The peer in which the service is run.
1082 struct GNUNET_TESTING_Peer *peer;
1085 * Closure for the above callback
1092 * Callback to be called when SCHEDULER has been started
1094 * @param cls the ServiceContext
1095 * @param tc the TaskContext
1098 service_run_main (void *cls,
1099 const struct GNUNET_SCHEDULER_TaskContext *tc)
1101 struct ServiceContext *sc = cls;
1103 sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1108 * Start a single service (no ARM, except of course if the given
1109 * service name is 'arm') and run a test using the testing library.
1110 * Starts a service using the given configuration and then invokes the
1111 * given callback. This function ALSO initializes the scheduler loop
1112 * and should thus be called directly from "main". The testcase
1113 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1115 * This function is useful if the testcase is for a single service
1116 * and if that service doesn't itself depend on other services.
1118 * @param testdir only the directory name without any path. This is used for
1119 * all service homes; the directory will be created in a temporary
1120 * location depending on the underlying OS
1121 * @param service_name name of the service to run
1122 * @param cfgfilename name of the configuration file to use;
1123 * use NULL to only run with defaults
1124 * @param tm main function of the testcase
1125 * @param tm_cls closure for 'tm'
1126 * @return 0 on success, 1 on error
1129 GNUNET_TESTING_service_run (const char *testdir,
1130 const char *service_name,
1131 const char *cfgfilename,
1132 GNUNET_TESTING_TestMain tm,
1135 struct ServiceContext sc;
1136 struct GNUNET_TESTING_System *system;
1137 struct GNUNET_TESTING_Peer *peer;
1138 struct GNUNET_CONFIGURATION_Handle *cfg;
1141 GNUNET_log_setup (testdir, "WARNING", NULL);
1142 system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL);
1145 cfg = GNUNET_CONFIGURATION_create ();
1146 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1148 LOG (GNUNET_ERROR_TYPE_ERROR,
1149 _("Failed to load configuration from %s\n"), cfgfilename);
1150 GNUNET_CONFIGURATION_destroy (cfg);
1151 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1154 peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1157 GNUNET_CONFIGURATION_destroy (cfg);
1158 hostkeys_unload (system);
1159 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1162 GNUNET_free (peer->main_binary);
1163 GNUNET_asprintf (&binary, "gnunet-service-%s", service_name);
1164 peer->main_binary = GNUNET_OS_get_libexec_binary_path (binary);
1165 GNUNET_free (binary);
1166 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1168 GNUNET_TESTING_peer_destroy (peer);
1169 GNUNET_CONFIGURATION_destroy (cfg);
1170 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1177 GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1178 if ((NULL != peer->main_process) &&
1179 (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1181 GNUNET_TESTING_peer_destroy (peer);
1182 GNUNET_CONFIGURATION_destroy (cfg);
1183 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1186 GNUNET_TESTING_peer_destroy (peer);
1187 GNUNET_CONFIGURATION_destroy (cfg);
1188 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1194 * Sometimes we use the binary name to determine which specific
1195 * test to run. In those cases, the string after the last "_"
1196 * in 'argv[0]' specifies a string that determines the configuration
1197 * file or plugin to use.
1199 * This function returns the respective substring, taking care
1200 * of issues such as binaries ending in '.exe' on W32.
1202 * @param argv0 the name of the binary
1203 * @return string between the last '_' and the '.exe' (or the end of the string),
1204 * NULL if argv0 has no '_'
1207 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1209 size_t slen = strlen (argv0) + 1;
1214 memcpy (sbuf, argv0, slen);
1215 ret = strrchr (sbuf, '_');
1218 ret++; /* skip underscore */
1219 dot = strchr (ret, '.');
1222 return GNUNET_strdup (ret);
1226 /* end of testing.c */