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, "gnunettestingnew", __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
77 * Hostkeys data, contains "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 % 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 / 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 lowport lowest port number this system is allowed to allocate (inclusive)
266 * @param highport highest port number this system is allowed to allocate (exclusive)
267 * @return handle to this system, NULL on error
269 struct GNUNET_TESTING_System *
270 GNUNET_TESTING_system_create_with_portrange (const char *testdir,
271 const char *controller,
275 struct GNUNET_TESTING_System *system;
277 GNUNET_assert (NULL != testdir);
278 system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
279 system->tmppath = GNUNET_DISK_mkdtemp (testdir);
280 system->lowport = lowport;
281 system->highport = highport;
282 if (NULL == system->tmppath)
284 GNUNET_free (system);
287 if (NULL != controller)
288 system->controller = GNUNET_strdup (controller);
289 if (GNUNET_OK != hostkeys_load (system))
291 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
299 * Create a system handle. There must only be one system
300 * handle per operating system.
302 * @param testdir only the directory name without any path. This is used for
303 * all service homes; the directory will be created in a temporary
304 * location depending on the underlying OS
306 * @param controller hostname of the controlling host,
307 * service configurations are modified to allow
308 * control connections from this host; can be NULL
309 * @return handle to this system, NULL on error
311 struct GNUNET_TESTING_System *
312 GNUNET_TESTING_system_create (const char *testdir,
313 const char *controller)
315 return GNUNET_TESTING_system_create_with_portrange (testdir,
323 * Free system resources.
325 * @param system system to be freed
326 * @param remove_paths should the 'testdir' and all subdirectories
327 * be removed (clean up on shutdown)?
330 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
333 if (NULL != system->hostkeys_data)
334 hostkeys_unload (system);
335 if (GNUNET_YES == remove_paths)
336 GNUNET_DISK_directory_remove (system->tmppath);
337 GNUNET_free (system->tmppath);
338 GNUNET_free_non_null (system->controller);
339 GNUNET_free (system);
344 * Reserve a TCP or UDP port for a peer.
346 * @param system system to use for reservation tracking
347 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
348 * @return 0 if no free port was available
351 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system,
354 struct GNUNET_NETWORK_Handle *socket;
355 struct addrinfo hint;
356 struct addrinfo *ret;
357 uint32_t *port_buckets;
366 FIXME: Instead of using getaddrinfo we should try to determine the port
367 status by the following heurestics.
369 On systems which support both IPv4 and IPv6, only ports open on both
370 address families are considered open.
371 On system with either IPv4 or IPv6. A port is considered open if it's
372 open in the respective address family
374 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
375 hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM;
376 hint.ai_protocol = 0;
379 hint.ai_canonname = NULL;
381 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
382 port_buckets = (GNUNET_YES == is_tcp) ?
383 system->reserved_tcp_ports : system->reserved_udp_ports;
384 for (index = (system->lowport / 32) + 1; index < (system->highport / 32); index++)
386 xor_image = (UINT32_MAX ^ port_buckets[index]);
387 if (0 == xor_image) /* Ports in the bucket are full */
389 pos = system->lowport % 32;
392 if (0 == ((xor_image >> pos) & 1U))
397 open_port = (index * 32) + pos;
398 if (open_port >= system->highport)
400 GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
402 GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
403 GNUNET_free (open_port_str);
404 socket = GNUNET_NETWORK_socket_create (ret->ai_family,
405 (GNUNET_YES == is_tcp) ?
406 SOCK_STREAM : SOCK_DGRAM,
408 GNUNET_assert (NULL != socket);
409 bind_status = GNUNET_NETWORK_socket_bind (socket,
413 GNUNET_NETWORK_socket_close (socket);
415 port_buckets[index] |= (1U << pos); /* Set the port bit */
416 if (GNUNET_OK == bind_status)
418 LOG (GNUNET_ERROR_TYPE_DEBUG,
419 "Found a free port %u\n", (unsigned int) open_port);
430 * Release reservation of a TCP or UDP port for a peer
431 * (used during GNUNET_TESTING_peer_destroy).
433 * @param system system to use for reservation tracking
434 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
435 * @param port reserved port to release
438 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
442 uint32_t *port_buckets;
446 port_buckets = (GNUNET_YES == is_tcp) ?
447 system->reserved_tcp_ports : system->reserved_udp_ports;
450 LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
451 if (0 == (port_buckets[bucket] & (1U << pos)))
453 GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
456 port_buckets[bucket] &= ~(1U << pos);
461 * Reserve a SERVICEHOME path for a peer.
463 * @param system system to use for reservation tracking
464 * @return NULL on error, otherwise fresh unique path to use
465 * as the servicehome for the peer; must be freed by the caller
469 reserve_path (struct GNUNET_TESTING_System *system)
473 GNUNET_asprintf (&reserved_path,
474 "%s/%u", system->tmppath, system->path_counter++);
475 return reserved_path;
480 * Testing includes a number of pre-created hostkeys for
481 * faster peer startup. This function can be used to
482 * access the n-th key of those pre-created hostkeys; note
483 * that these keys are ONLY useful for testing and not
484 * secure as the private keys are part of the public
485 * GNUnet source code.
487 * This is primarily a helper function used internally
488 * by 'GNUNET_TESTING_peer_configure'.
490 * @param system the testing system handle
491 * @param key_number desired pre-created hostkey to obtain
492 * @param id set to the peer's identity (hash of the public
493 * key; if NULL, GNUNET_SYSERR is returned immediately
494 * @return NULL on error (not enough keys)
496 struct GNUNET_CRYPTO_RsaPrivateKey *
497 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
499 struct GNUNET_PeerIdentity *id)
501 struct GNUNET_CRYPTO_RsaPrivateKey *private_key;
502 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
504 if ((NULL == id) || (NULL == system->hostkeys_data))
506 if (key_number >= system->total_hostkeys)
508 LOG (GNUNET_ERROR_TYPE_ERROR,
509 _("Key number %u does not exist\n"), key_number);
512 private_key = GNUNET_CRYPTO_rsa_decode_key (system->hostkeys_data +
513 (key_number * HOSTKEYFILESIZE),
515 if (NULL == private_key)
517 LOG (GNUNET_ERROR_TYPE_ERROR,
518 _("Error while decoding key %u\n"), key_number);
521 GNUNET_CRYPTO_rsa_key_get_public (private_key, &public_key);
522 GNUNET_CRYPTO_hash (&public_key,
523 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
530 * Structure for holding data to build new configurations from a configuration
536 * The system for which we are building configurations
538 struct GNUNET_TESTING_System *system;
541 * The configuration we are building
543 struct GNUNET_CONFIGURATION_Handle *cfg;
546 * The customized service home path for this peer
551 * build status - to signal error while building a configuration
558 * Function to iterate over options. Copies
559 * the options to the target configuration,
560 * updating PORT values as needed.
562 * @param cls the UpdateContext
563 * @param section name of the section
564 * @param option name of the option
565 * @param value value of the option
568 update_config (void *cls, const char *section, const char *option,
571 struct UpdateContext *uc = cls;
575 char *single_variable;
576 char *per_host_variable;
577 unsigned long long num_per_host;
580 if (GNUNET_OK != uc->status)
582 if (! ((0 == strcmp (option, "PORT"))
583 || (0 == strcmp (option, "UNIXPATH"))
584 || (0 == strcmp (option, "HOSTNAME"))))
586 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
587 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
588 if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
592 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
595 /* FIXME: What about UDP? */
596 new_port = GNUNET_TESTING_reserve_port (uc->system, GNUNET_YES);
599 uc->status = GNUNET_SYSERR;
602 GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
605 else if ((ival != 0) &&
607 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
609 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
613 /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
614 /* ival + ctx->fdnum % num_per_host); */
616 GNUNET_break (0); /* FIXME */
619 if (0 == strcmp (option, "UNIXPATH"))
622 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
625 GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock",
626 uc->service_home, section);
629 else if ((GNUNET_YES ==
630 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
635 GNUNET_break(0); /* FIXME */
638 if ((0 == strcmp (option, "HOSTNAME")) && (NULL != uc->system->controller))
640 value = uc->system->controller;
642 GNUNET_free (single_variable);
643 GNUNET_free (per_host_variable);
644 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
649 * Section iterator to set ACCEPT_FROM/ACCEPT_FROM6 depending on the ip of the
650 * controller in all sections
652 * @param cls the UpdateContext
653 * @param section name of the section
656 update_config_sections (void *cls,
659 struct UpdateContext *uc = cls;
663 char *orig_allowed_hosts;
665 char *ACCEPT_FROM_key;
671 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
672 "TESTING_IGNORE_KEYS"))
676 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section,
677 "TESTING_IGNORE_KEYS", &val));
679 for (ikeys_cnt = 0; NULL != (ptr = strstr (ptr, ";")); ikeys_cnt++)
685 ikeys = GNUNET_malloc ((sizeof (char *)) * ikeys_cnt);
687 for (key = 0; key < ikeys_cnt; key++)
690 ptr = strstr (ptr, ";");
698 for (key = 0; key < ikeys_cnt; key++)
700 if (NULL != strstr (ikeys[key], "ADVERTISED_PORT"))
703 if ((key == ikeys_cnt) &&
704 (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
708 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "PORT", &ptr))
710 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section,
711 "ADVERTISED_PORT", ptr);
715 for (key = 0; key < ikeys_cnt; key++)
717 if (NULL != strstr (ikeys[key], "ACCEPT_FROM"))
726 GNUNET_free_non_null (val);
727 ACCEPT_FROM_key = "ACCEPT_FROM";
728 if ((NULL != uc->system->controller) &&
729 (NULL != strstr (uc->system->controller, ":"))) /* IPv6 in use */
730 ACCEPT_FROM_key = "ACCEPT_FROM6";
732 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, ACCEPT_FROM_key,
733 &orig_allowed_hosts))
735 orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
737 if (NULL == uc->system->controller)
738 allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
740 GNUNET_asprintf (&allowed_hosts, "%s%s;", orig_allowed_hosts,
741 uc->system->controller);
742 GNUNET_free (orig_allowed_hosts);
743 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, ACCEPT_FROM_key,
745 GNUNET_free (allowed_hosts);
750 * Create a new configuration using the given configuration as a template;
751 * ports and paths will be modified to select available ports on the local
752 * system. The default configuration will be available in PATHS section under
753 * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS
754 * section to the temporary directory specific to this configuration. If we run
755 * out of "*port" numbers, return SYSERR.
757 * This is primarily a helper function used internally
758 * by 'GNUNET_TESTING_peer_configure'.
760 * @param system system to use to coordinate resource usage
761 * @param cfg template configuration to update
762 * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
763 * be incomplete and should not be used there upon
766 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
767 struct GNUNET_CONFIGURATION_Handle *cfg)
769 struct UpdateContext uc;
770 char *default_config;
774 uc.status = GNUNET_OK;
775 GNUNET_asprintf (&uc.service_home, "%s/%u", system->tmppath,
776 system->path_counter++);
777 GNUNET_asprintf (&default_config, "%s/config", uc.service_home);
778 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
780 GNUNET_free (default_config);
781 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME",
783 /* make PORTs and UNIXPATHs unique */
784 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
785 /* allow connections to services from system controller host */
786 GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
787 /* enable loopback-based connections between peers */
788 GNUNET_CONFIGURATION_set_value_string (cfg,
790 "USE_LOCALADDR", "YES");
791 GNUNET_free (uc.service_home);
797 * Configure a GNUnet peer. GNUnet must be installed on the local
798 * system and available in the PATH.
800 * @param system system to use to coordinate resource usage
801 * @param cfg configuration to use; will be UPDATED (to reflect needed
802 * changes in port numbers and paths)
803 * @param key_number number of the hostkey to use for the peer
804 * @param id identifier for the daemon, will be set, can be NULL
805 * @param emsg set to freshly allocated error message (set to NULL on success),
807 * @return handle to the peer, NULL on error
809 struct GNUNET_TESTING_Peer *
810 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
811 struct GNUNET_CONFIGURATION_Handle *cfg,
813 struct GNUNET_PeerIdentity *id,
816 struct GNUNET_TESTING_Peer *peer;
817 struct GNUNET_DISK_FileHandle *fd;
819 char hostkey_filename[128];
820 char *config_filename;
822 struct GNUNET_CRYPTO_RsaPrivateKey *pk;
826 if (GNUNET_OK != GNUNET_TESTING_configuration_create (system, cfg))
828 GNUNET_asprintf (&emsg_,
829 _("Failed to create configuration for peer (not enough free ports?)\n"));
830 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
837 if (key_number >= system->total_hostkeys)
839 GNUNET_asprintf (&emsg_,
840 _("You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"),
841 (unsigned int) system->total_hostkeys);
842 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
851 (NULL == (pk = GNUNET_TESTING_hostkey_get (system, key_number, id))))
853 GNUNET_asprintf (&emsg_,
854 _("Failed to initialize hostkey for peer %u\n"),
855 (unsigned int) key_number);
856 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
864 GNUNET_CRYPTO_rsa_key_free (pk);
865 GNUNET_assert (GNUNET_OK ==
866 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
869 GNUNET_snprintf (hostkey_filename, sizeof (hostkey_filename), "%s/.hostkey",
871 GNUNET_free (service_home);
872 fd = GNUNET_DISK_file_open (hostkey_filename,
873 GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
874 GNUNET_DISK_PERM_USER_READ
875 | GNUNET_DISK_PERM_USER_WRITE);
881 if (HOSTKEYFILESIZE !=
882 GNUNET_DISK_file_write (fd, system->hostkeys_data
883 + (key_number * HOSTKEYFILESIZE),
886 GNUNET_asprintf (&emsg_,
887 _("Failed to write hostkey file for peer %u: %s\n"),
888 (unsigned int) key_number,
890 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
895 GNUNET_DISK_file_close (fd);
898 GNUNET_DISK_file_close (fd);
899 GNUNET_assert (GNUNET_OK ==
900 GNUNET_CONFIGURATION_get_value_string
901 (cfg, "PATHS", "DEFAULTCONFIG", &config_filename));
902 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
904 GNUNET_asprintf (&emsg_,
905 _("Failed to write configuration file `%s' for peer %u: %s\n"),
907 (unsigned int) key_number,
909 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
914 GNUNET_free (config_filename);
917 peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
918 peer->cfgfile = config_filename; /* Free in peer_destroy */
919 peer->main_binary = GNUNET_strdup ("gnunet-service-arm");
920 peer->system = system;
921 peer->key_number = key_number;
927 * Obtain the peer identity from a peer handle.
929 * @param peer peer handle for which we want the peer's identity
930 * @param id identifier for the daemon, will be set
933 GNUNET_TESTING_peer_get_identity (const struct GNUNET_TESTING_Peer *peer,
934 struct GNUNET_PeerIdentity *id)
936 GNUNET_CRYPTO_rsa_key_free (GNUNET_TESTING_hostkey_get (peer->system,
945 * @param peer peer to start
946 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
949 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
951 if (NULL != peer->main_process)
954 return GNUNET_SYSERR;
956 GNUNET_assert (NULL != peer->cfgfile);
957 peer->main_process = GNUNET_OS_start_process (GNUNET_YES, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL,
963 if (NULL == peer->main_process)
965 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
966 _("Failed to start `%s': %s\n"),
969 return GNUNET_SYSERR;
978 * @param peer peer to stop
979 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer not running)
982 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
984 if (NULL == peer->main_process)
987 return GNUNET_SYSERR;
989 (void) GNUNET_OS_process_kill (peer->main_process, SIGTERM);
990 GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (peer->main_process));
991 GNUNET_OS_process_destroy (peer->main_process);
992 peer->main_process = NULL;
998 * Destroy the peer. Releases resources locked during peer configuration.
999 * If the peer is still running, it will be stopped AND a warning will be
1000 * printed (users of the API should stop the peer explicitly first).
1002 * @param peer peer to destroy
1005 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
1007 if (NULL != peer->main_process)
1010 GNUNET_TESTING_peer_stop (peer);
1012 GNUNET_free (peer->cfgfile);
1013 GNUNET_free (peer->main_binary);
1019 * Start a single peer and run a test using the testing library.
1020 * Starts a peer using the given configuration and then invokes the
1021 * given callback. This function ALSO initializes the scheduler loop
1022 * and should thus be called directly from "main". The testcase
1023 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1025 * @param testdir only the directory name without any path. This is used for
1026 * all service homes; the directory will be created in a temporary
1027 * location depending on the underlying OS
1028 * @param cfgfilename name of the configuration file to use;
1029 * use NULL to only run with defaults
1030 * @param tm main function of the testcase
1031 * @param tm_cls closure for 'tm'
1032 * @return 0 on success, 1 on error
1035 GNUNET_TESTING_peer_run (const char *testdir,
1036 const char *cfgfilename,
1037 GNUNET_TESTING_TestMain tm,
1040 return GNUNET_TESTING_service_run (testdir, "arm",
1041 cfgfilename, tm, tm_cls);
1046 * Structure for holding service data
1048 struct ServiceContext
1051 * The configuration of the peer in which the service is run
1053 const struct GNUNET_CONFIGURATION_Handle *cfg;
1056 * Callback to signal service startup
1058 GNUNET_TESTING_TestMain tm;
1061 * The peer in which the service is run.
1063 struct GNUNET_TESTING_Peer *peer;
1066 * Closure for the above callback
1073 * Callback to be called when SCHEDULER has been started
1075 * @param cls the ServiceContext
1076 * @param tc the TaskContext
1079 service_run_main (void *cls,
1080 const struct GNUNET_SCHEDULER_TaskContext *tc)
1082 struct ServiceContext *sc = cls;
1084 sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1089 * Start a single service (no ARM, except of course if the given
1090 * service name is 'arm') and run a test using the testing library.
1091 * Starts a service using the given configuration and then invokes the
1092 * given callback. This function ALSO initializes the scheduler loop
1093 * and should thus be called directly from "main". The testcase
1094 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1096 * This function is useful if the testcase is for a single service
1097 * and if that service doesn't itself depend on other services.
1099 * @param testdir only the directory name without any path. This is used for
1100 * all service homes; the directory will be created in a temporary
1101 * location depending on the underlying OS
1102 * @param service_name name of the service to run
1103 * @param cfgfilename name of the configuration file to use;
1104 * use NULL to only run with defaults
1105 * @param tm main function of the testcase
1106 * @param tm_cls closure for 'tm'
1107 * @return 0 on success, 1 on error
1110 GNUNET_TESTING_service_run (const char *testdir,
1111 const char *service_name,
1112 const char *cfgfilename,
1113 GNUNET_TESTING_TestMain tm,
1116 struct ServiceContext sc;
1117 struct GNUNET_TESTING_System *system;
1118 struct GNUNET_TESTING_Peer *peer;
1119 struct GNUNET_CONFIGURATION_Handle *cfg;
1121 GNUNET_log_setup (testdir, "WARNING", NULL);
1122 system = GNUNET_TESTING_system_create (testdir, "127.0.0.1");
1125 cfg = GNUNET_CONFIGURATION_create ();
1126 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1128 LOG (GNUNET_ERROR_TYPE_ERROR,
1129 _("Failed to load configuration from %s\n"), cfgfilename);
1130 GNUNET_CONFIGURATION_destroy (cfg);
1131 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1134 peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1137 GNUNET_CONFIGURATION_destroy (cfg);
1138 hostkeys_unload (system);
1139 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1142 GNUNET_free (peer->main_binary);
1143 GNUNET_asprintf (&peer->main_binary, "gnunet-service-%s", service_name);
1144 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1146 GNUNET_TESTING_peer_destroy (peer);
1147 GNUNET_CONFIGURATION_destroy (cfg);
1148 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1155 GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1156 if ((NULL != peer->main_process) &&
1157 (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1159 GNUNET_TESTING_peer_destroy (peer);
1160 GNUNET_CONFIGURATION_destroy (cfg);
1161 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1164 GNUNET_TESTING_peer_destroy (peer);
1165 GNUNET_CONFIGURATION_destroy (cfg);
1166 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1172 * Sometimes we use the binary name to determine which specific
1173 * test to run. In those cases, the string after the last "_"
1174 * in 'argv[0]' specifies a string that determines the configuration
1175 * file or plugin to use.
1177 * This function returns the respective substring, taking care
1178 * of issues such as binaries ending in '.exe' on W32.
1180 * @param argv0 the name of the binary
1181 * @return string between the last '_' and the '.exe' (or the end of the string),
1182 * NULL if argv0 has no '_'
1185 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1187 size_t slen = strlen (argv0) + 1;
1192 memcpy (sbuf, argv0, slen);
1193 ret = strrchr (sbuf, '_');
1196 ret++; /* skip underscore */
1197 dot = strchr (ret, '.');
1200 return GNUNET_strdup (ret);
1204 /* end of testing.c */