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 * Size of a hostkey when written to a file
42 #define HOSTKEYFILESIZE 914
45 * Lowest port used for GNUnet testing. Should be high enough to not
46 * conflict with other applications running on the hosts but be low
47 * enough to not conflict with client-ports (typically starting around
50 #define LOW_PORT 12000
53 * Highest port used for GNUnet testing. Should be low enough to not
54 * conflict with the port range for "local" ports (client apps; see
55 * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
57 #define HIGH_PORT 56000
61 * Handle for a system on which GNUnet peers are executed;
62 * a system is used for reserving unique paths and ports.
64 struct GNUNET_TESTING_System
67 * Prefix (i.e. "/tmp/gnunet-testing/") we prepend to each
72 * The hostname of the controller
82 * Hostkeys data, contains "HOSTKEYFILESIZE * total_hostkeys" bytes.
87 * memory map for 'hostkeys_data'.
89 struct GNUNET_DISK_MapHandle *map;
92 * File descriptor for the map.
94 struct GNUNET_DISK_FileHandle *map_fd;
97 * Bitmap where each TCP port that has already been reserved for
98 * some GNUnet peer is recorded. Note that we additionally need to
99 * test if a port is already in use by non-GNUnet components before
100 * assigning it to a peer/service. If we detect that a port is
101 * already in use, we also mark it in this bitmap. So all the bits
102 * that are zero merely indicate ports that MIGHT be available for
105 uint32_t reserved_tcp_ports[65536 / 32];
108 * Bitmap where each UDP port that has already been reserved for
109 * some GNUnet peer is recorded. Note that we additionally need to
110 * test if a port is already in use by non-GNUnet components before
111 * assigning it to a peer/service. If we detect that a port is
112 * already in use, we also mark it in this bitmap. So all the bits
113 * that are zero merely indicate ports that MIGHT be available for
116 uint32_t reserved_udp_ports[65536 / 32];
119 * Counter we use to make service home paths unique on this system;
120 * the full path consists of the tmppath and this number. Each
121 * UNIXPATH for a peer is also modified to include the respective
122 * path counter to ensure uniqueness. This field is incremented
123 * by one for each configured peer. Even if peers are destroyed,
124 * we never re-use path counters.
126 uint32_t path_counter;
129 * The number of hostkeys
131 uint32_t total_hostkeys;
134 * Lowest port we are allowed to use.
139 * Highest port we are allowed to use.
146 * Handle for a GNUnet peer controlled by testing.
148 struct GNUNET_TESTING_Peer
151 * The TESTING system associated with this peer
153 struct GNUNET_TESTING_System *system;
156 * Path to the configuration file for this peer.
161 * Binary to be executed during 'GNUNET_TESTING_peer_start'.
162 * Typically 'gnunet-service-arm' (but can be set to a
163 * specific service by 'GNUNET_TESTING_service_run' if
169 * Handle to the running binary of the service, NULL if the
170 * peer/service is currently not running.
172 struct GNUNET_OS_Process *main_process;
175 * The keynumber of this peer's hostkey
182 * Testing includes a number of pre-created hostkeys for faster peer
183 * startup. This function loads such keys into memory from a file.
185 * @param system the testing system handle
186 * @return GNUNET_OK on success; GNUNET_SYSERR on error
189 hostkeys_load (struct GNUNET_TESTING_System *system)
195 GNUNET_assert (NULL == system->hostkeys_data);
196 data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
197 GNUNET_asprintf (&filename, "%s/testing_hostkeys.dat", data_dir);
198 GNUNET_free (data_dir);
200 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
202 LOG (GNUNET_ERROR_TYPE_ERROR,
203 _("Hostkeys file not found: %s\n"), filename);
204 GNUNET_free (filename);
205 return GNUNET_SYSERR;
207 /* Check hostkey file size, read entire thing into memory */
209 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
213 GNUNET_free (filename);
214 return GNUNET_SYSERR; /* File is empty */
216 if (0 != (fs % HOSTKEYFILESIZE))
218 LOG (GNUNET_ERROR_TYPE_ERROR,
219 _("Incorrect hostkey file format: %s\n"), filename);
220 GNUNET_free (filename);
221 return GNUNET_SYSERR;
223 system->map_fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
224 GNUNET_DISK_PERM_NONE);
225 if (NULL == system->map_fd)
227 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename);
228 GNUNET_free (filename);
229 return GNUNET_SYSERR;
231 system->total_hostkeys = fs / HOSTKEYFILESIZE;
232 system->hostkeys_data = GNUNET_DISK_file_map (system->map_fd,
234 GNUNET_DISK_MAP_TYPE_READ,
236 GNUNET_free (filename);
242 * Function to remove the loaded hostkeys
244 * @param system the testing system handle
247 hostkeys_unload (struct GNUNET_TESTING_System *system)
249 GNUNET_break (NULL != system->hostkeys_data);
250 system->hostkeys_data = NULL;
251 GNUNET_DISK_file_unmap (system->map);
253 GNUNET_DISK_file_close (system->map_fd);
254 system->map_fd = NULL;
255 system->hostkeys_data = NULL;
256 system->total_hostkeys = 0;
261 * Create a system handle. There must only be one system
262 * handle per operating system.
264 * @param testdir only the directory name without any path. This is used for
265 * all service homes; the directory will be created in a temporary
266 * location depending on the underlying OS
267 * @param controller hostname of the controlling host,
268 * service configurations are modified to allow
269 * control connections from this host; can be NULL
270 * @param hostname the hostname of the system we are using for testing; NULL for
272 * @param lowport lowest port number this system is allowed to allocate (inclusive)
273 * @param highport highest port number this system is allowed to allocate (exclusive)
274 * @return handle to this system, NULL on error
276 struct GNUNET_TESTING_System *
277 GNUNET_TESTING_system_create_with_portrange (const char *testdir,
278 const char *controller,
279 const char *hostname,
283 struct GNUNET_TESTING_System *system;
285 GNUNET_assert (NULL != testdir);
286 system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
287 system->tmppath = GNUNET_DISK_mkdtemp (testdir);
288 system->lowport = lowport;
289 system->highport = highport;
290 if (NULL == system->tmppath)
292 GNUNET_free (system);
295 if (NULL != controller)
296 system->controller = GNUNET_strdup (controller);
297 if (NULL != hostname)
298 system->hostname = GNUNET_strdup (hostname);
299 if (GNUNET_OK != hostkeys_load (system))
301 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
309 * Create a system handle. There must only be one system handle per operating
310 * system. Uses a default range for allowed ports. Ports are still tested for
313 * @param testdir only the directory name without any path. This is used for all
314 * service homes; the directory will be created in a temporary location
315 * depending on the underlying OS
316 * @param controller hostname of the controlling host, service configurations
317 * are modified to allow control connections from this host; can be NULL
318 * @param hostname the hostname of the system we are using for testing; NULL for
320 * @return handle to this system, NULL on error
322 struct GNUNET_TESTING_System *
323 GNUNET_TESTING_system_create (const char *testdir,
324 const char *controller,
325 const char *hostname)
327 return GNUNET_TESTING_system_create_with_portrange (testdir,
336 * Free system resources.
338 * @param system system to be freed
339 * @param remove_paths should the 'testdir' and all subdirectories
340 * be removed (clean up on shutdown)?
343 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
346 if (NULL != system->hostkeys_data)
347 hostkeys_unload (system);
348 if (GNUNET_YES == remove_paths)
349 GNUNET_DISK_directory_remove (system->tmppath);
350 GNUNET_free (system->tmppath);
351 GNUNET_free_non_null (system->controller);
352 GNUNET_free_non_null (system->hostname);
353 GNUNET_free (system);
358 * Reserve a TCP or UDP port for a peer.
360 * @param system system to use for reservation tracking
361 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
362 * @return 0 if no free port was available
365 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system,
368 struct GNUNET_NETWORK_Handle *socket;
369 struct addrinfo hint;
370 struct addrinfo *ret;
371 uint32_t *port_buckets;
380 FIXME: Instead of using getaddrinfo we should try to determine the port
381 status by the following heurestics.
383 On systems which support both IPv4 and IPv6, only ports open on both
384 address families are considered open.
385 On system with either IPv4 or IPv6. A port is considered open if it's
386 open in the respective address family
388 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
389 hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM;
390 hint.ai_protocol = 0;
393 hint.ai_canonname = NULL;
395 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
396 port_buckets = (GNUNET_YES == is_tcp) ?
397 system->reserved_tcp_ports : system->reserved_udp_ports;
398 for (index = (system->lowport / 32) + 1; index < (system->highport / 32); index++)
400 xor_image = (UINT32_MAX ^ port_buckets[index]);
401 if (0 == xor_image) /* Ports in the bucket are full */
403 pos = system->lowport % 32;
406 if (0 == ((xor_image >> pos) & 1U))
411 open_port = (index * 32) + pos;
412 if (open_port >= system->highport)
414 GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
416 GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
417 GNUNET_free (open_port_str);
418 socket = GNUNET_NETWORK_socket_create (ret->ai_family,
419 (GNUNET_YES == is_tcp) ?
420 SOCK_STREAM : SOCK_DGRAM,
422 GNUNET_assert (NULL != socket);
423 bind_status = GNUNET_NETWORK_socket_bind (socket,
427 GNUNET_NETWORK_socket_close (socket);
429 port_buckets[index] |= (1U << pos); /* Set the port bit */
430 if (GNUNET_OK == bind_status)
432 LOG (GNUNET_ERROR_TYPE_DEBUG,
433 "Found a free port %u\n", (unsigned int) open_port);
444 * Release reservation of a TCP or UDP port for a peer
445 * (used during GNUNET_TESTING_peer_destroy).
447 * @param system system to use for reservation tracking
448 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
449 * @param port reserved port to release
452 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
456 uint32_t *port_buckets;
460 port_buckets = (GNUNET_YES == is_tcp) ?
461 system->reserved_tcp_ports : system->reserved_udp_ports;
464 LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
465 if (0 == (port_buckets[bucket] & (1U << pos)))
467 GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
470 port_buckets[bucket] &= ~(1U << pos);
475 * Reserve a SERVICEHOME path for a peer.
477 * @param system system to use for reservation tracking
478 * @return NULL on error, otherwise fresh unique path to use
479 * as the servicehome for the peer; must be freed by the caller
483 reserve_path (struct GNUNET_TESTING_System *system)
487 GNUNET_asprintf (&reserved_path,
488 "%s/%u", system->tmppath, system->path_counter++);
489 return reserved_path;
494 * Testing includes a number of pre-created hostkeys for
495 * faster peer startup. This function can be used to
496 * access the n-th key of those pre-created hostkeys; note
497 * that these keys are ONLY useful for testing and not
498 * secure as the private keys are part of the public
499 * GNUnet source code.
501 * This is primarily a helper function used internally
502 * by 'GNUNET_TESTING_peer_configure'.
504 * @param system the testing system handle
505 * @param key_number desired pre-created hostkey to obtain
506 * @param id set to the peer's identity (hash of the public
507 * key; if NULL, GNUNET_SYSERR is returned immediately
508 * @return NULL on error (not enough keys)
510 struct GNUNET_CRYPTO_RsaPrivateKey *
511 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
513 struct GNUNET_PeerIdentity *id)
515 struct GNUNET_CRYPTO_RsaPrivateKey *private_key;
516 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
518 if ((NULL == id) || (NULL == system->hostkeys_data))
520 if (key_number >= system->total_hostkeys)
522 LOG (GNUNET_ERROR_TYPE_ERROR,
523 _("Key number %u does not exist\n"), key_number);
526 private_key = GNUNET_CRYPTO_rsa_decode_key (system->hostkeys_data +
527 (key_number * HOSTKEYFILESIZE),
529 if (NULL == private_key)
531 LOG (GNUNET_ERROR_TYPE_ERROR,
532 _("Error while decoding key %u\n"), key_number);
535 GNUNET_CRYPTO_rsa_key_get_public (private_key, &public_key);
536 GNUNET_CRYPTO_hash (&public_key,
537 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
544 * Structure for holding data to build new configurations from a configuration
550 * The system for which we are building configurations
552 struct GNUNET_TESTING_System *system;
555 * The configuration we are building
557 struct GNUNET_CONFIGURATION_Handle *cfg;
560 * The customized service home path for this peer
565 * build status - to signal error while building a configuration
572 * Function to iterate over options. Copies
573 * the options to the target configuration,
574 * updating PORT values as needed.
576 * @param cls the UpdateContext
577 * @param section name of the section
578 * @param option name of the option
579 * @param value value of the option
582 update_config (void *cls, const char *section, const char *option,
585 struct UpdateContext *uc = cls;
589 char *single_variable;
590 char *per_host_variable;
591 unsigned long long num_per_host;
594 if (GNUNET_OK != uc->status)
596 if (! ((0 == strcmp (option, "PORT"))
597 || (0 == strcmp (option, "UNIXPATH"))
598 || (0 == strcmp (option, "HOSTNAME"))))
600 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
601 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
602 if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
606 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
609 /* FIXME: What about UDP? */
610 new_port = GNUNET_TESTING_reserve_port (uc->system, GNUNET_YES);
613 uc->status = GNUNET_SYSERR;
616 GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
619 else if ((ival != 0) &&
621 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
623 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
627 /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
628 /* ival + ctx->fdnum % num_per_host); */
630 GNUNET_break (0); /* FIXME */
633 if (0 == strcmp (option, "UNIXPATH"))
636 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
639 GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock",
640 uc->service_home, section);
643 else if ((GNUNET_YES ==
644 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
649 GNUNET_break(0); /* FIXME */
652 if (0 == strcmp (option, "HOSTNAME"))
654 value = (NULL == uc->system->hostname) ? "localhost" : uc->system->hostname;
656 GNUNET_free (single_variable);
657 GNUNET_free (per_host_variable);
658 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
663 * Section iterator to set ACCEPT_FROM/ACCEPT_FROM6 depending on the ip of the
664 * controller in all sections
666 * @param cls the UpdateContext
667 * @param section name of the section
670 update_config_sections (void *cls,
673 struct UpdateContext *uc = cls;
677 char *orig_allowed_hosts;
679 char *ACCEPT_FROM_key;
685 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
686 "TESTING_IGNORE_KEYS"))
690 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section,
691 "TESTING_IGNORE_KEYS", &val));
693 for (ikeys_cnt = 0; NULL != (ptr = strstr (ptr, ";")); ikeys_cnt++)
699 ikeys = GNUNET_malloc ((sizeof (char *)) * ikeys_cnt);
701 for (key = 0; key < ikeys_cnt; key++)
704 ptr = strstr (ptr, ";");
712 for (key = 0; key < ikeys_cnt; key++)
714 if (NULL != strstr (ikeys[key], "ADVERTISED_PORT"))
717 if ((key == ikeys_cnt) &&
718 (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
722 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "PORT", &ptr))
724 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section,
725 "ADVERTISED_PORT", ptr);
729 for (key = 0; key < ikeys_cnt; key++)
731 if (NULL != strstr (ikeys[key], "ACCEPT_FROM"))
740 GNUNET_free_non_null (val);
741 ACCEPT_FROM_key = "ACCEPT_FROM";
742 if ((NULL != uc->system->controller) &&
743 (NULL != strstr (uc->system->controller, ":"))) /* IPv6 in use */
744 ACCEPT_FROM_key = "ACCEPT_FROM6";
746 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, ACCEPT_FROM_key,
747 &orig_allowed_hosts))
749 orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
751 if (NULL == uc->system->controller)
752 allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
754 GNUNET_asprintf (&allowed_hosts, "%s%s;", orig_allowed_hosts,
755 uc->system->controller);
756 GNUNET_free (orig_allowed_hosts);
757 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, ACCEPT_FROM_key,
759 GNUNET_free (allowed_hosts);
764 * Create a new configuration using the given configuration as a template;
765 * ports and paths will be modified to select available ports on the local
766 * system. The default configuration will be available in PATHS section under
767 * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS
768 * section to the temporary directory specific to this configuration. If we run
769 * out of "*port" numbers, return SYSERR.
771 * This is primarily a helper function used internally
772 * by 'GNUNET_TESTING_peer_configure'.
774 * @param system system to use to coordinate resource usage
775 * @param cfg template configuration to update
776 * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
777 * be incomplete and should not be used there upon
780 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
781 struct GNUNET_CONFIGURATION_Handle *cfg)
783 struct UpdateContext uc;
784 char *default_config;
788 uc.status = GNUNET_OK;
789 GNUNET_asprintf (&uc.service_home, "%s/%u", system->tmppath,
790 system->path_counter++);
791 GNUNET_asprintf (&default_config, "%s/config", uc.service_home);
792 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
794 GNUNET_free (default_config);
795 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME",
797 /* make PORTs and UNIXPATHs unique */
798 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
799 /* allow connections to services from system controller host */
800 GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
801 /* enable loopback-based connections between peers */
802 GNUNET_CONFIGURATION_set_value_string (cfg,
804 "USE_LOCALADDR", "YES");
805 GNUNET_free (uc.service_home);
811 * Configure a GNUnet peer. GNUnet must be installed on the local
812 * system and available in the PATH.
814 * @param system system to use to coordinate resource usage
815 * @param cfg configuration to use; will be UPDATED (to reflect needed
816 * changes in port numbers and paths)
817 * @param key_number number of the hostkey to use for the peer
818 * @param id identifier for the daemon, will be set, can be NULL
819 * @param emsg set to freshly allocated error message (set to NULL on success),
821 * @return handle to the peer, NULL on error
823 struct GNUNET_TESTING_Peer *
824 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
825 struct GNUNET_CONFIGURATION_Handle *cfg,
827 struct GNUNET_PeerIdentity *id,
830 struct GNUNET_TESTING_Peer *peer;
831 struct GNUNET_DISK_FileHandle *fd;
833 char hostkey_filename[128];
834 char *config_filename;
836 struct GNUNET_CRYPTO_RsaPrivateKey *pk;
840 if (GNUNET_OK != GNUNET_TESTING_configuration_create (system, cfg))
842 GNUNET_asprintf (&emsg_,
843 _("Failed to create configuration for peer (not enough free ports?)\n"));
844 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
851 if (key_number >= system->total_hostkeys)
853 GNUNET_asprintf (&emsg_,
854 _("You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"),
855 (unsigned int) system->total_hostkeys);
856 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
865 (NULL == (pk = GNUNET_TESTING_hostkey_get (system, key_number, id))))
867 GNUNET_asprintf (&emsg_,
868 _("Failed to initialize hostkey for peer %u\n"),
869 (unsigned int) key_number);
870 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
878 GNUNET_CRYPTO_rsa_key_free (pk);
879 GNUNET_assert (GNUNET_OK ==
880 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
883 GNUNET_snprintf (hostkey_filename, sizeof (hostkey_filename), "%s/.hostkey",
885 GNUNET_free (service_home);
886 fd = GNUNET_DISK_file_open (hostkey_filename,
887 GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
888 GNUNET_DISK_PERM_USER_READ
889 | GNUNET_DISK_PERM_USER_WRITE);
895 if (HOSTKEYFILESIZE !=
896 GNUNET_DISK_file_write (fd, system->hostkeys_data
897 + (key_number * HOSTKEYFILESIZE),
900 GNUNET_asprintf (&emsg_,
901 _("Failed to write hostkey file for peer %u: %s\n"),
902 (unsigned int) key_number,
904 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
909 GNUNET_DISK_file_close (fd);
912 GNUNET_DISK_file_close (fd);
913 GNUNET_assert (GNUNET_OK ==
914 GNUNET_CONFIGURATION_get_value_string
915 (cfg, "PATHS", "DEFAULTCONFIG", &config_filename));
916 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
918 GNUNET_asprintf (&emsg_,
919 _("Failed to write configuration file `%s' for peer %u: %s\n"),
921 (unsigned int) key_number,
923 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
928 GNUNET_free (config_filename);
931 peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
932 peer->cfgfile = config_filename; /* Free in peer_destroy */
933 peer->main_binary = GNUNET_strdup ("gnunet-service-arm");
934 peer->system = system;
935 peer->key_number = key_number;
941 * Obtain the peer identity from a peer handle.
943 * @param peer peer handle for which we want the peer's identity
944 * @param id identifier for the daemon, will be set
947 GNUNET_TESTING_peer_get_identity (const struct GNUNET_TESTING_Peer *peer,
948 struct GNUNET_PeerIdentity *id)
950 GNUNET_CRYPTO_rsa_key_free (GNUNET_TESTING_hostkey_get (peer->system,
959 * @param peer peer to start
960 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
963 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
965 if (NULL != peer->main_process)
968 return GNUNET_SYSERR;
970 GNUNET_assert (NULL != peer->cfgfile);
971 peer->main_process = GNUNET_OS_start_process (GNUNET_YES, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL,
977 if (NULL == peer->main_process)
979 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
980 _("Failed to start `%s': %s\n"),
983 return GNUNET_SYSERR;
992 * @param peer peer to stop
993 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer not running)
996 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
998 if (NULL == peer->main_process)
1001 return GNUNET_SYSERR;
1003 (void) GNUNET_OS_process_kill (peer->main_process, SIGTERM);
1004 GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (peer->main_process));
1005 GNUNET_OS_process_destroy (peer->main_process);
1006 peer->main_process = NULL;
1012 * Destroy the peer. Releases resources locked during peer configuration.
1013 * If the peer is still running, it will be stopped AND a warning will be
1014 * printed (users of the API should stop the peer explicitly first).
1016 * @param peer peer to destroy
1019 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
1021 if (NULL != peer->main_process)
1024 GNUNET_TESTING_peer_stop (peer);
1026 GNUNET_free (peer->cfgfile);
1027 GNUNET_free (peer->main_binary);
1033 * Start a single peer and run a test using the testing library.
1034 * Starts a peer using the given configuration and then invokes the
1035 * given callback. This function ALSO initializes the scheduler loop
1036 * and should thus be called directly from "main". The testcase
1037 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1039 * @param testdir only the directory name without any path. This is used for
1040 * all service homes; the directory will be created in a temporary
1041 * location depending on the underlying OS
1042 * @param cfgfilename name of the configuration file to use;
1043 * use NULL to only run with defaults
1044 * @param tm main function of the testcase
1045 * @param tm_cls closure for 'tm'
1046 * @return 0 on success, 1 on error
1049 GNUNET_TESTING_peer_run (const char *testdir,
1050 const char *cfgfilename,
1051 GNUNET_TESTING_TestMain tm,
1054 return GNUNET_TESTING_service_run (testdir, "arm",
1055 cfgfilename, tm, tm_cls);
1060 * Structure for holding service data
1062 struct ServiceContext
1065 * The configuration of the peer in which the service is run
1067 const struct GNUNET_CONFIGURATION_Handle *cfg;
1070 * Callback to signal service startup
1072 GNUNET_TESTING_TestMain tm;
1075 * The peer in which the service is run.
1077 struct GNUNET_TESTING_Peer *peer;
1080 * Closure for the above callback
1087 * Callback to be called when SCHEDULER has been started
1089 * @param cls the ServiceContext
1090 * @param tc the TaskContext
1093 service_run_main (void *cls,
1094 const struct GNUNET_SCHEDULER_TaskContext *tc)
1096 struct ServiceContext *sc = cls;
1098 sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1103 * Start a single service (no ARM, except of course if the given
1104 * service name is 'arm') and run a test using the testing library.
1105 * Starts a service using the given configuration and then invokes the
1106 * given callback. This function ALSO initializes the scheduler loop
1107 * and should thus be called directly from "main". The testcase
1108 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1110 * This function is useful if the testcase is for a single service
1111 * and if that service doesn't itself depend on other services.
1113 * @param testdir only the directory name without any path. This is used for
1114 * all service homes; the directory will be created in a temporary
1115 * location depending on the underlying OS
1116 * @param service_name name of the service to run
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_service_run (const char *testdir,
1125 const char *service_name,
1126 const char *cfgfilename,
1127 GNUNET_TESTING_TestMain tm,
1130 struct ServiceContext sc;
1131 struct GNUNET_TESTING_System *system;
1132 struct GNUNET_TESTING_Peer *peer;
1133 struct GNUNET_CONFIGURATION_Handle *cfg;
1135 GNUNET_log_setup (testdir, "WARNING", NULL);
1136 system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL);
1139 cfg = GNUNET_CONFIGURATION_create ();
1140 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1142 LOG (GNUNET_ERROR_TYPE_ERROR,
1143 _("Failed to load configuration from %s\n"), cfgfilename);
1144 GNUNET_CONFIGURATION_destroy (cfg);
1145 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1148 peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1151 GNUNET_CONFIGURATION_destroy (cfg);
1152 hostkeys_unload (system);
1153 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1156 GNUNET_free (peer->main_binary);
1157 GNUNET_asprintf (&peer->main_binary, "gnunet-service-%s", service_name);
1158 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1160 GNUNET_TESTING_peer_destroy (peer);
1161 GNUNET_CONFIGURATION_destroy (cfg);
1162 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1169 GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1170 if ((NULL != peer->main_process) &&
1171 (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1173 GNUNET_TESTING_peer_destroy (peer);
1174 GNUNET_CONFIGURATION_destroy (cfg);
1175 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1178 GNUNET_TESTING_peer_destroy (peer);
1179 GNUNET_CONFIGURATION_destroy (cfg);
1180 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1186 * Sometimes we use the binary name to determine which specific
1187 * test to run. In those cases, the string after the last "_"
1188 * in 'argv[0]' specifies a string that determines the configuration
1189 * file or plugin to use.
1191 * This function returns the respective substring, taking care
1192 * of issues such as binaries ending in '.exe' on W32.
1194 * @param argv0 the name of the binary
1195 * @return string between the last '_' and the '.exe' (or the end of the string),
1196 * NULL if argv0 has no '_'
1199 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1201 size_t slen = strlen (argv0) + 1;
1206 memcpy (sbuf, argv0, slen);
1207 ret = strrchr (sbuf, '_');
1210 ret++; /* skip underscore */
1211 dot = strchr (ret, '.');
1214 return GNUNET_strdup (ret);
1218 /* end of testing.c */