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
165 * Handle to the running binary of the service, NULL if the
166 * peer/service is currently not running.
168 struct GNUNET_OS_Process *main_process;
171 * The keynumber of this peer's hostkey
178 * Testing includes a number of pre-created hostkeys for faster peer
179 * startup. This function loads such keys into memory from a file.
181 * @param system the testing system handle
182 * @return GNUNET_OK on success; GNUNET_SYSERR on error
185 hostkeys_load (struct GNUNET_TESTING_System *system)
191 GNUNET_assert (NULL == system->hostkeys_data);
192 data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
193 GNUNET_asprintf (&filename, "%s/testing_hostkeys.dat", data_dir);
194 GNUNET_free (data_dir);
196 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
198 LOG (GNUNET_ERROR_TYPE_ERROR,
199 _("Hostkeys file not found: %s\n"), filename);
200 GNUNET_free (filename);
201 return GNUNET_SYSERR;
203 /* Check hostkey file size, read entire thing into memory */
205 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
209 GNUNET_free (filename);
210 return GNUNET_SYSERR; /* File is empty */
212 if (0 != (fs % GNUNET_TESTING_HOSTKEYFILESIZE))
214 LOG (GNUNET_ERROR_TYPE_ERROR,
215 _("Incorrect hostkey file format: %s\n"), filename);
216 GNUNET_free (filename);
217 return GNUNET_SYSERR;
219 system->map_fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
220 GNUNET_DISK_PERM_NONE);
221 if (NULL == system->map_fd)
223 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename);
224 GNUNET_free (filename);
225 return GNUNET_SYSERR;
227 system->total_hostkeys = fs / GNUNET_TESTING_HOSTKEYFILESIZE;
228 system->hostkeys_data = GNUNET_DISK_file_map (system->map_fd,
230 GNUNET_DISK_MAP_TYPE_READ,
232 GNUNET_free (filename);
238 * Function to remove the loaded hostkeys
240 * @param system the testing system handle
243 hostkeys_unload (struct GNUNET_TESTING_System *system)
245 GNUNET_break (NULL != system->hostkeys_data);
246 system->hostkeys_data = NULL;
247 GNUNET_DISK_file_unmap (system->map);
249 GNUNET_DISK_file_close (system->map_fd);
250 system->map_fd = NULL;
251 system->hostkeys_data = NULL;
252 system->total_hostkeys = 0;
257 * Create a system handle. There must only be one system
258 * handle per operating system.
260 * @param testdir only the directory name without any path. This is used for
261 * all service homes; the directory will be created in a temporary
262 * location depending on the underlying OS
263 * @param controller hostname of the controlling host,
264 * service configurations are modified to allow
265 * control connections from this host; can be NULL
266 * @param hostname the hostname of the system we are using for testing; NULL for
268 * @param lowport lowest port number this system is allowed to allocate (inclusive)
269 * @param highport highest port number this system is allowed to allocate (exclusive)
270 * @return handle to this system, NULL on error
272 struct GNUNET_TESTING_System *
273 GNUNET_TESTING_system_create_with_portrange (const char *testdir,
274 const char *controller,
275 const char *hostname,
279 struct GNUNET_TESTING_System *system;
281 GNUNET_assert (NULL != testdir);
282 system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
283 system->tmppath = GNUNET_DISK_mkdtemp (testdir);
284 system->lowport = lowport;
285 system->highport = highport;
286 if (NULL == system->tmppath)
288 GNUNET_free (system);
291 if (NULL != controller)
292 system->controller = GNUNET_strdup (controller);
293 if (NULL != hostname)
294 system->hostname = GNUNET_strdup (hostname);
295 if (GNUNET_OK != hostkeys_load (system))
297 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
305 * Create a system handle. There must only be one system handle per operating
306 * system. Uses a default range for allowed ports. Ports are still tested for
309 * @param testdir only the directory name without any path. This is used for all
310 * service homes; the directory will be created in a temporary location
311 * depending on the underlying OS
312 * @param controller hostname of the controlling host, service configurations
313 * are modified to allow control connections from this host; can be NULL
314 * @param hostname the hostname of the system we are using for testing; NULL for
316 * @return handle to this system, NULL on error
318 struct GNUNET_TESTING_System *
319 GNUNET_TESTING_system_create (const char *testdir,
320 const char *controller,
321 const char *hostname)
323 return GNUNET_TESTING_system_create_with_portrange (testdir,
332 * Free system resources.
334 * @param system system to be freed
335 * @param remove_paths should the 'testdir' and all subdirectories
336 * be removed (clean up on shutdown)?
339 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
342 if (NULL != system->hostkeys_data)
343 hostkeys_unload (system);
344 if (GNUNET_YES == remove_paths)
345 GNUNET_DISK_directory_remove (system->tmppath);
346 GNUNET_free (system->tmppath);
347 GNUNET_free_non_null (system->controller);
348 GNUNET_free_non_null (system->hostname);
349 GNUNET_free (system);
354 * Reserve a TCP or UDP port for a peer.
356 * @param system system to use for reservation tracking
357 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
358 * @return 0 if no free port was available
361 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system,
364 struct GNUNET_NETWORK_Handle *socket;
365 struct addrinfo hint;
366 struct addrinfo *ret;
368 uint32_t *port_buckets;
377 FIXME: Instead of using getaddrinfo we should try to determine the port
378 status by the following heurestics.
380 On systems which support both IPv4 and IPv6, only ports open on both
381 address families are considered open.
382 On system with either IPv4 or IPv6. A port is considered open if it's
383 open in the respective address family
385 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
386 hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM;
387 hint.ai_protocol = 0;
390 hint.ai_canonname = NULL;
392 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
393 port_buckets = (GNUNET_YES == is_tcp) ?
394 system->reserved_tcp_ports : system->reserved_udp_ports;
395 for (index = (system->lowport / 32) + 1; index < (system->highport / 32); index++)
397 xor_image = (UINT32_MAX ^ port_buckets[index]);
398 if (0 == xor_image) /* Ports in the bucket are full */
400 pos = system->lowport % 32;
403 if (0 == ((xor_image >> pos) & 1U))
408 open_port = (index * 32) + pos;
409 if (open_port >= system->highport)
411 GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
413 GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
414 GNUNET_free (open_port_str);
415 bind_status = GNUNET_NO;
416 for (ai = ret; NULL != ai; ai = ai->ai_next)
418 socket = GNUNET_NETWORK_socket_create (ai->ai_family,
419 (GNUNET_YES == is_tcp) ?
420 SOCK_STREAM : SOCK_DGRAM,
424 bind_status = GNUNET_NETWORK_socket_bind (socket,
427 GNUNET_NETWORK_socket_close (socket);
428 if (GNUNET_OK != bind_status)
431 port_buckets[index] |= (1U << pos); /* Set the port bit */
433 if (GNUNET_OK == bind_status)
435 LOG (GNUNET_ERROR_TYPE_DEBUG,
436 "Found a free port %u\n", (unsigned int) open_port);
447 * Release reservation of a TCP or UDP port for a peer
448 * (used during GNUNET_TESTING_peer_destroy).
450 * @param system system to use for reservation tracking
451 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
452 * @param port reserved port to release
455 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
459 uint32_t *port_buckets;
463 port_buckets = (GNUNET_YES == is_tcp) ?
464 system->reserved_tcp_ports : system->reserved_udp_ports;
467 LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
468 if (0 == (port_buckets[bucket] & (1U << pos)))
470 GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
473 port_buckets[bucket] &= ~(1U << pos);
478 * Reserve a SERVICEHOME path for a peer.
480 * @param system system to use for reservation tracking
481 * @return NULL on error, otherwise fresh unique path to use
482 * as the servicehome for the peer; must be freed by the caller
486 reserve_path (struct GNUNET_TESTING_System *system)
490 GNUNET_asprintf (&reserved_path,
491 "%s/%u", system->tmppath, system->path_counter++);
492 return reserved_path;
497 * Testing includes a number of pre-created hostkeys for
498 * faster peer startup. This function can be used to
499 * access the n-th key of those pre-created hostkeys; note
500 * that these keys are ONLY useful for testing and not
501 * secure as the private keys are part of the public
502 * GNUnet source code.
504 * This is primarily a helper function used internally
505 * by 'GNUNET_TESTING_peer_configure'.
507 * @param system the testing system handle
508 * @param key_number desired pre-created hostkey to obtain
509 * @param id set to the peer's identity (hash of the public
510 * key; if NULL, GNUNET_SYSERR is returned immediately
511 * @return NULL on error (not enough keys)
513 struct GNUNET_CRYPTO_RsaPrivateKey *
514 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
516 struct GNUNET_PeerIdentity *id)
518 struct GNUNET_CRYPTO_RsaPrivateKey *private_key;
519 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
521 if ((NULL == id) || (NULL == system->hostkeys_data))
523 if (key_number >= system->total_hostkeys)
525 LOG (GNUNET_ERROR_TYPE_ERROR,
526 _("Key number %u does not exist\n"), key_number);
529 private_key = GNUNET_CRYPTO_rsa_decode_key (system->hostkeys_data +
531 GNUNET_TESTING_HOSTKEYFILESIZE),
532 GNUNET_TESTING_HOSTKEYFILESIZE);
533 if (NULL == private_key)
535 LOG (GNUNET_ERROR_TYPE_ERROR,
536 _("Error while decoding key %u\n"), key_number);
539 GNUNET_CRYPTO_rsa_key_get_public (private_key, &public_key);
540 GNUNET_CRYPTO_hash (&public_key,
541 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
548 * Structure for holding data to build new configurations from a configuration
554 * The system for which we are building configurations
556 struct GNUNET_TESTING_System *system;
559 * The configuration we are building
561 struct GNUNET_CONFIGURATION_Handle *cfg;
564 * The customized service home path for this peer
569 * build status - to signal error while building a configuration
576 * Function to iterate over options. Copies
577 * the options to the target configuration,
578 * updating PORT values as needed.
580 * @param cls the UpdateContext
581 * @param section name of the section
582 * @param option name of the option
583 * @param value value of the option
586 update_config (void *cls, const char *section, const char *option,
589 struct UpdateContext *uc = cls;
593 char *single_variable;
594 char *per_host_variable;
595 unsigned long long num_per_host;
598 if (GNUNET_OK != uc->status)
600 if (! ((0 == strcmp (option, "PORT"))
601 || (0 == strcmp (option, "UNIXPATH"))
602 || (0 == strcmp (option, "HOSTNAME"))))
604 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
605 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
606 if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
610 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
613 /* FIXME: What about UDP? */
614 new_port = GNUNET_TESTING_reserve_port (uc->system, GNUNET_YES);
617 uc->status = GNUNET_SYSERR;
618 GNUNET_free (single_variable);
619 GNUNET_free (per_host_variable);
622 GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
625 else if ((ival != 0) &&
627 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
629 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
633 /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
634 /* ival + ctx->fdnum % num_per_host); */
636 GNUNET_break (0); /* FIXME */
639 if (0 == strcmp (option, "UNIXPATH"))
642 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
645 GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock",
646 uc->service_home, section);
649 else if ((GNUNET_YES ==
650 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
655 GNUNET_break(0); /* FIXME */
658 if (0 == strcmp (option, "HOSTNAME"))
660 value = (NULL == uc->system->hostname) ? "localhost" : uc->system->hostname;
662 GNUNET_free (single_variable);
663 GNUNET_free (per_host_variable);
664 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
669 * Section iterator to set ACCEPT_FROM/ACCEPT_FROM6 depending on the ip of the
670 * controller in all sections
672 * @param cls the UpdateContext
673 * @param section name of the section
676 update_config_sections (void *cls,
679 struct UpdateContext *uc = cls;
683 char *orig_allowed_hosts;
685 char *ACCEPT_FROM_key;
691 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
692 "TESTING_IGNORE_KEYS"))
696 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section,
697 "TESTING_IGNORE_KEYS", &val));
699 for (ikeys_cnt = 0; NULL != (ptr = strstr (ptr, ";")); ikeys_cnt++)
705 ikeys = GNUNET_malloc ((sizeof (char *)) * ikeys_cnt);
707 for (key = 0; key < ikeys_cnt; key++)
710 ptr = strstr (ptr, ";");
718 for (key = 0; key < ikeys_cnt; key++)
720 if (NULL != strstr (ikeys[key], "ADVERTISED_PORT"))
723 if ((key == ikeys_cnt) &&
724 (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
728 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "PORT", &ptr))
730 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section,
731 "ADVERTISED_PORT", ptr);
735 for (key = 0; key < ikeys_cnt; key++)
737 if (NULL != strstr (ikeys[key], "ACCEPT_FROM"))
746 GNUNET_free_non_null (val);
747 ACCEPT_FROM_key = "ACCEPT_FROM";
748 if ((NULL != uc->system->controller) &&
749 (NULL != strstr (uc->system->controller, ":"))) /* IPv6 in use */
750 ACCEPT_FROM_key = "ACCEPT_FROM6";
752 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, ACCEPT_FROM_key,
753 &orig_allowed_hosts))
755 orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
757 if (NULL == uc->system->controller)
758 allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
760 GNUNET_asprintf (&allowed_hosts, "%s%s;", orig_allowed_hosts,
761 uc->system->controller);
762 GNUNET_free (orig_allowed_hosts);
763 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, ACCEPT_FROM_key,
765 GNUNET_free (allowed_hosts);
770 * Create a new configuration using the given configuration as a template;
771 * ports and paths will be modified to select available ports on the local
772 * system. The default configuration will be available in PATHS section under
773 * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS
774 * section to the temporary directory specific to this configuration. If we run
775 * out of "*port" numbers, return SYSERR.
777 * This is primarily a helper function used internally
778 * by 'GNUNET_TESTING_peer_configure'.
780 * @param system system to use to coordinate resource usage
781 * @param cfg template configuration to update
782 * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
783 * be incomplete and should not be used there upon
786 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
787 struct GNUNET_CONFIGURATION_Handle *cfg)
789 struct UpdateContext uc;
790 char *default_config;
794 uc.status = GNUNET_OK;
795 GNUNET_asprintf (&uc.service_home, "%s/%u", system->tmppath,
796 system->path_counter++);
797 GNUNET_asprintf (&default_config, "%s/config", uc.service_home);
798 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
800 GNUNET_free (default_config);
801 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME",
803 /* make PORTs and UNIXPATHs unique */
804 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
805 /* allow connections to services from system controller host */
806 GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
807 /* enable loopback-based connections between peers */
808 GNUNET_CONFIGURATION_set_value_string (cfg,
810 "USE_LOCALADDR", "YES");
811 GNUNET_free (uc.service_home);
817 * Configure a GNUnet peer. GNUnet must be installed on the local
818 * system and available in the PATH.
820 * @param system system to use to coordinate resource usage
821 * @param cfg configuration to use; will be UPDATED (to reflect needed
822 * changes in port numbers and paths)
823 * @param key_number number of the hostkey to use for the peer
824 * @param id identifier for the daemon, will be set, can be NULL
825 * @param emsg set to freshly allocated error message (set to NULL on success),
827 * @return handle to the peer, NULL on error
829 struct GNUNET_TESTING_Peer *
830 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
831 struct GNUNET_CONFIGURATION_Handle *cfg,
833 struct GNUNET_PeerIdentity *id,
836 struct GNUNET_TESTING_Peer *peer;
837 struct GNUNET_DISK_FileHandle *fd;
839 char hostkey_filename[128];
840 char *config_filename;
841 char *libexec_binary;
843 struct GNUNET_CRYPTO_RsaPrivateKey *pk;
847 if (GNUNET_OK != GNUNET_TESTING_configuration_create (system, cfg))
849 GNUNET_asprintf (&emsg_,
850 _("Failed to create configuration for peer (not enough free ports?)\n"));
851 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
858 if (key_number >= system->total_hostkeys)
860 GNUNET_asprintf (&emsg_,
861 _("You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"),
862 (unsigned int) system->total_hostkeys);
863 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
872 (NULL == (pk = GNUNET_TESTING_hostkey_get (system, key_number, id))))
874 GNUNET_asprintf (&emsg_,
875 _("Failed to initialize hostkey for peer %u\n"),
876 (unsigned int) key_number);
877 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
885 GNUNET_CRYPTO_rsa_key_free (pk);
886 GNUNET_assert (GNUNET_OK ==
887 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
890 GNUNET_snprintf (hostkey_filename, sizeof (hostkey_filename), "%s/.hostkey",
892 GNUNET_free (service_home);
893 fd = GNUNET_DISK_file_open (hostkey_filename,
894 GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
895 GNUNET_DISK_PERM_USER_READ
896 | GNUNET_DISK_PERM_USER_WRITE);
902 if (GNUNET_TESTING_HOSTKEYFILESIZE !=
903 GNUNET_DISK_file_write (fd, system->hostkeys_data
904 + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE),
905 GNUNET_TESTING_HOSTKEYFILESIZE))
907 GNUNET_asprintf (&emsg_,
908 _("Failed to write hostkey file for peer %u: %s\n"),
909 (unsigned int) key_number,
911 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
916 GNUNET_DISK_file_close (fd);
919 GNUNET_DISK_file_close (fd);
920 GNUNET_assert (GNUNET_OK ==
921 GNUNET_CONFIGURATION_get_value_string
922 (cfg, "PATHS", "DEFAULTCONFIG", &config_filename));
923 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
925 GNUNET_asprintf (&emsg_,
926 _("Failed to write configuration file `%s' for peer %u: %s\n"),
928 (unsigned int) key_number,
930 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
935 GNUNET_free (config_filename);
938 peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
939 peer->cfgfile = config_filename; /* Free in peer_destroy */
940 libexec_binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
941 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "arm", "PREFIX", &peer->main_binary))
944 GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
945 peer->args = strdup ("");
948 peer->args = strdup (libexec_binary);
949 peer->system = system;
950 peer->key_number = key_number;
951 GNUNET_free (libexec_binary);
957 * Obtain the peer identity from a peer handle.
959 * @param peer peer handle for which we want the peer's identity
960 * @param id identifier for the daemon, will be set
963 GNUNET_TESTING_peer_get_identity (const struct GNUNET_TESTING_Peer *peer,
964 struct GNUNET_PeerIdentity *id)
966 GNUNET_CRYPTO_rsa_key_free (GNUNET_TESTING_hostkey_get (peer->system,
975 * @param peer peer to start
976 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
979 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
981 if (NULL != peer->main_process)
984 return GNUNET_SYSERR;
986 GNUNET_assert (NULL != peer->cfgfile);
987 peer->main_process = GNUNET_OS_start_process (GNUNET_YES, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL,
994 if (NULL == peer->main_process)
996 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
997 _("Failed to start `%s': %s\n"),
1000 return GNUNET_SYSERR;
1007 * Sends SIGTERM to the peer's main process
1009 * @param peer the handle to the peer
1010 * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1011 * or upon any error while sending SIGTERM
1014 GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer)
1016 if (NULL == peer->main_process)
1019 return GNUNET_SYSERR;
1021 return (0 == GNUNET_OS_process_kill (peer->main_process, SIGTERM)) ?
1022 GNUNET_OK : GNUNET_SYSERR;
1027 * Waits for a peer to terminate. The peer's main process will also be destroyed.
1029 * @param peer the handle to the peer
1030 * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1031 * or upon any error while waiting
1034 GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer)
1038 if (NULL == peer->main_process)
1041 return GNUNET_SYSERR;
1043 ret = GNUNET_OS_process_wait (peer->main_process);
1044 GNUNET_OS_process_destroy (peer->main_process);
1045 peer->main_process = NULL;
1053 * @param peer peer to stop
1054 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1057 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
1059 if (GNUNET_SYSERR == GNUNET_TESTING_peer_kill (peer))
1060 return GNUNET_SYSERR;
1061 if (GNUNET_SYSERR == GNUNET_TESTING_peer_wait (peer))
1062 return GNUNET_SYSERR;
1068 * Destroy the peer. Releases resources locked during peer configuration.
1069 * If the peer is still running, it will be stopped AND a warning will be
1070 * printed (users of the API should stop the peer explicitly first).
1072 * @param peer peer to destroy
1075 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
1077 if (NULL != peer->main_process)
1080 GNUNET_TESTING_peer_stop (peer);
1082 GNUNET_free (peer->cfgfile);
1083 GNUNET_free (peer->main_binary);
1084 GNUNET_free (peer->args);
1090 * Start a single peer and run a test using the testing library.
1091 * Starts a peer 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 * @param testdir only the directory name without any path. This is used for
1097 * all service homes; the directory will be created in a temporary
1098 * location depending on the underlying OS
1099 * @param cfgfilename name of the configuration file to use;
1100 * use NULL to only run with defaults
1101 * @param tm main function of the testcase
1102 * @param tm_cls closure for 'tm'
1103 * @return 0 on success, 1 on error
1106 GNUNET_TESTING_peer_run (const char *testdir,
1107 const char *cfgfilename,
1108 GNUNET_TESTING_TestMain tm,
1111 return GNUNET_TESTING_service_run (testdir, "arm",
1112 cfgfilename, tm, tm_cls);
1117 * Structure for holding service data
1119 struct ServiceContext
1122 * The configuration of the peer in which the service is run
1124 const struct GNUNET_CONFIGURATION_Handle *cfg;
1127 * Callback to signal service startup
1129 GNUNET_TESTING_TestMain tm;
1132 * The peer in which the service is run.
1134 struct GNUNET_TESTING_Peer *peer;
1137 * Closure for the above callback
1144 * Callback to be called when SCHEDULER has been started
1146 * @param cls the ServiceContext
1147 * @param tc the TaskContext
1150 service_run_main (void *cls,
1151 const struct GNUNET_SCHEDULER_TaskContext *tc)
1153 struct ServiceContext *sc = cls;
1155 sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1160 * Start a single service (no ARM, except of course if the given
1161 * service name is 'arm') and run a test using the testing library.
1162 * Starts a service using the given configuration and then invokes the
1163 * given callback. This function ALSO initializes the scheduler loop
1164 * and should thus be called directly from "main". The testcase
1165 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1167 * This function is useful if the testcase is for a single service
1168 * and if that service doesn't itself depend on other services.
1170 * @param testdir only the directory name without any path. This is used for
1171 * all service homes; the directory will be created in a temporary
1172 * location depending on the underlying OS
1173 * @param service_name name of the service to run
1174 * @param cfgfilename name of the configuration file to use;
1175 * use NULL to only run with defaults
1176 * @param tm main function of the testcase
1177 * @param tm_cls closure for 'tm'
1178 * @return 0 on success, 1 on error
1181 GNUNET_TESTING_service_run (const char *testdir,
1182 const char *service_name,
1183 const char *cfgfilename,
1184 GNUNET_TESTING_TestMain tm,
1187 struct ServiceContext sc;
1188 struct GNUNET_TESTING_System *system;
1189 struct GNUNET_TESTING_Peer *peer;
1190 struct GNUNET_CONFIGURATION_Handle *cfg;
1192 char *libexec_binary;
1194 GNUNET_log_setup (testdir, "WARNING", NULL);
1195 system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL);
1198 cfg = GNUNET_CONFIGURATION_create ();
1199 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1201 LOG (GNUNET_ERROR_TYPE_ERROR,
1202 _("Failed to load configuration from %s\n"), cfgfilename);
1203 GNUNET_CONFIGURATION_destroy (cfg);
1204 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1207 peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1210 GNUNET_CONFIGURATION_destroy (cfg);
1211 hostkeys_unload (system);
1212 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1215 GNUNET_free (peer->main_binary);
1216 GNUNET_free (peer->args);
1217 GNUNET_asprintf (&binary, "gnunet-service-%s", service_name);
1218 libexec_binary = GNUNET_OS_get_libexec_binary_path (binary);
1219 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, service_name, "PREFIX", &peer->main_binary))
1222 GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1223 peer->args = strdup ("");
1226 peer->args = strdup (libexec_binary);
1228 GNUNET_free (libexec_binary);
1229 GNUNET_free (binary);
1230 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1232 GNUNET_TESTING_peer_destroy (peer);
1233 GNUNET_CONFIGURATION_destroy (cfg);
1234 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1241 GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1242 if ((NULL != peer->main_process) &&
1243 (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1245 GNUNET_TESTING_peer_destroy (peer);
1246 GNUNET_CONFIGURATION_destroy (cfg);
1247 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1250 GNUNET_TESTING_peer_destroy (peer);
1251 GNUNET_CONFIGURATION_destroy (cfg);
1252 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1258 * Sometimes we use the binary name to determine which specific
1259 * test to run. In those cases, the string after the last "_"
1260 * in 'argv[0]' specifies a string that determines the configuration
1261 * file or plugin to use.
1263 * This function returns the respective substring, taking care
1264 * of issues such as binaries ending in '.exe' on W32.
1266 * @param argv0 the name of the binary
1267 * @return string between the last '_' and the '.exe' (or the end of the string),
1268 * NULL if argv0 has no '_'
1271 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1273 size_t slen = strlen (argv0) + 1;
1278 memcpy (sbuf, argv0, slen);
1279 ret = strrchr (sbuf, '_');
1282 ret++; /* skip underscore */
1283 dot = strchr (ret, '.');
1286 return GNUNET_strdup (ret);
1290 /* end of testing.c */