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_arm_service.h"
35 #include "gnunet_testing_lib.h"
37 #define LOG(kind,...) \
38 GNUNET_log_from (kind, "testing-api", __VA_ARGS__)
42 * We need pipe control only on WINDOWS
45 #define PIPE_CONTROL GNUNET_YES
47 #define PIPE_CONTROL GNUNET_NO
52 * Lowest port used for GNUnet testing. Should be high enough to not
53 * conflict with other applications running on the hosts but be low
54 * enough to not conflict with client-ports (typically starting around
57 #define LOW_PORT 12000
60 * Highest port used for GNUnet testing. Should be low enough to not
61 * conflict with the port range for "local" ports (client apps; see
62 * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
64 #define HIGH_PORT 56000
68 * Handle for a system on which GNUnet peers are executed;
69 * a system is used for reserving unique paths and ports.
71 struct GNUNET_TESTING_System
74 * Prefix (i.e. "/tmp/gnunet-testing/") we prepend to each
79 * The trusted ip. Can either be a single ip address or a network address in
90 * Hostkeys data, contains "GNUNET_TESTING_HOSTKEYFILESIZE * total_hostkeys" bytes.
95 * Bitmap where each TCP port that has already been reserved for
96 * some GNUnet peer is recorded. Note that we additionally need to
97 * test if a port is already in use by non-GNUnet components before
98 * assigning it to a peer/service. If we detect that a port is
99 * already in use, we also mark it in this bitmap. So all the bits
100 * that are zero merely indicate ports that MIGHT be available for
103 uint32_t reserved_tcp_ports[65536 / 32];
106 * Bitmap where each UDP port that has already been reserved for
107 * some GNUnet peer is recorded. Note that we additionally need to
108 * test if a port is already in use by non-GNUnet components before
109 * assigning it to a peer/service. If we detect that a port is
110 * already in use, we also mark it in this bitmap. So all the bits
111 * that are zero merely indicate ports that MIGHT be available for
114 uint32_t reserved_udp_ports[65536 / 32];
117 * Counter we use to make service home paths unique on this system;
118 * the full path consists of the tmppath and this number. Each
119 * UNIXPATH for a peer is also modified to include the respective
120 * path counter to ensure uniqueness. This field is incremented
121 * by one for each configured peer. Even if peers are destroyed,
122 * we never re-use path counters.
124 uint32_t path_counter;
127 * The number of hostkeys
129 uint32_t total_hostkeys;
132 * Lowest port we are allowed to use.
137 * Highest port we are allowed to use.
144 * Handle for a GNUnet peer controlled by testing.
146 struct GNUNET_TESTING_Peer
149 * The TESTING system associated with this peer
151 struct GNUNET_TESTING_System *system;
154 * Path to the configuration file for this peer.
159 * Binary to be executed during 'GNUNET_TESTING_peer_start'.
160 * Typically 'gnunet-service-arm' (but can be set to a
161 * specific service by 'GNUNET_TESTING_service_run' if
168 * Handle to the running binary of the service, NULL if the
169 * peer/service is currently not running.
171 struct GNUNET_OS_Process *main_process;
174 * The handle to the peer's ARM service
176 struct GNUNET_ARM_Handle *ah;
179 * Handle to ARM monitoring
181 struct GNUNET_ARM_MonitorHandle *mh;
184 * The config of the peer
186 struct GNUNET_CONFIGURATION_Handle *cfg;
189 * The callback to call asynchronously when a peer is stopped
191 GNUNET_TESTING_PeerStopCallback cb;
194 * The closure for the above callback
199 * The cached identity of this peer. Will be populated on call to
200 * GNUNET_TESTING_peer_get_identity()
202 struct GNUNET_PeerIdentity *id;
205 * Array of ports currently allocated to this peer. These ports will be
206 * released upon peer destroy and can be used by other peers which are
212 * The number of ports in the above array
217 * The keynumber of this peer's hostkey
224 * Testing includes a number of pre-created hostkeys for faster peer
225 * startup. This function loads such keys into memory from a file.
227 * @param system the testing system handle
228 * @return GNUNET_OK on success; GNUNET_SYSERR on error
231 hostkeys_load (struct GNUNET_TESTING_System *system)
237 GNUNET_assert (NULL == system->hostkeys_data);
238 data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
239 GNUNET_asprintf (&filename, "%s/testing_hostkeys.ecc", data_dir);
240 GNUNET_free (data_dir);
242 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
244 LOG (GNUNET_ERROR_TYPE_ERROR,
245 _("Hostkeys file not found: %s\n"), filename);
246 GNUNET_free (filename);
247 return GNUNET_SYSERR;
249 /* Check hostkey file size, read entire thing into memory */
251 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
255 GNUNET_free (filename);
256 return GNUNET_SYSERR; /* File is empty */
258 if (0 != (fs % GNUNET_TESTING_HOSTKEYFILESIZE))
260 LOG (GNUNET_ERROR_TYPE_ERROR,
261 _("Incorrect hostkey file format: %s\n"), filename);
262 GNUNET_free (filename);
263 return GNUNET_SYSERR;
265 system->hostkeys_data = GNUNET_malloc_large ((size_t) fs);
266 if (GNUNET_DISK_fn_read (filename, system->hostkeys_data, fs) != (ssize_t) fs)
268 GNUNET_free (filename);
269 GNUNET_free (system->hostkeys_data);
270 system->hostkeys_data = NULL;
271 return GNUNET_SYSERR;
273 system->total_hostkeys = fs / GNUNET_TESTING_HOSTKEYFILESIZE;
274 GNUNET_free (filename);
280 * Function to remove the loaded hostkeys
282 * @param system the testing system handle
285 hostkeys_unload (struct GNUNET_TESTING_System *system)
287 GNUNET_break (NULL != system->hostkeys_data);
288 GNUNET_free_non_null (system->hostkeys_data);
289 system->hostkeys_data = NULL;
290 system->total_hostkeys = 0;
295 * Create a system handle. There must only be one system
296 * handle per operating system.
298 * @param testdir only the directory name without any path. This is used for
299 * all service homes; the directory will be created in a temporary
300 * location depending on the underlying OS
301 * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
302 * service configurations generated to allow control connections from
303 * this ip. This can either be a single ip address or a network address
305 * @param hostname the hostname of the system we are using for testing; NULL for
307 * @param lowport lowest port number this system is allowed to allocate (inclusive)
308 * @param highport highest port number this system is allowed to allocate (exclusive)
309 * @return handle to this system, NULL on error
311 struct GNUNET_TESTING_System *
312 GNUNET_TESTING_system_create_with_portrange (const char *testdir,
313 const char *trusted_ip,
314 const char *hostname,
318 struct GNUNET_TESTING_System *system;
320 GNUNET_assert (NULL != testdir);
321 system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
322 system->tmppath = GNUNET_DISK_mkdtemp (testdir);
323 system->lowport = lowport;
324 system->highport = highport;
325 if (NULL == system->tmppath)
327 GNUNET_free (system);
330 if (NULL != trusted_ip)
331 system->trusted_ip = GNUNET_strdup (trusted_ip);
332 if (NULL != hostname)
333 system->hostname = GNUNET_strdup (hostname);
334 if (GNUNET_OK != hostkeys_load (system))
336 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
344 * Create a system handle. There must only be one system handle per operating
345 * system. Uses a default range for allowed ports. Ports are still tested for
348 * @param testdir only the directory name without any path. This is used for all
349 * service homes; the directory will be created in a temporary location
350 * depending on the underlying OS
351 * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
352 * service configurations generated to allow control connections from
353 * this ip. This can either be a single ip address or a network address
355 * @param hostname the hostname of the system we are using for testing; NULL for
357 * @return handle to this system, NULL on error
359 struct GNUNET_TESTING_System *
360 GNUNET_TESTING_system_create (const char *testdir,
361 const char *trusted_ip,
362 const char *hostname)
364 return GNUNET_TESTING_system_create_with_portrange (testdir,
373 * Free system resources.
375 * @param system system to be freed
376 * @param remove_paths should the 'testdir' and all subdirectories
377 * be removed (clean up on shutdown)?
380 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
383 if (NULL != system->hostkeys_data)
384 hostkeys_unload (system);
385 if (GNUNET_YES == remove_paths)
386 GNUNET_DISK_directory_remove (system->tmppath);
387 GNUNET_free (system->tmppath);
388 GNUNET_free_non_null (system->trusted_ip);
389 GNUNET_free_non_null (system->hostname);
390 GNUNET_free (system);
395 * Reserve a TCP or UDP port for a peer.
397 * @param system system to use for reservation tracking
398 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
399 * @return 0 if no free port was available
402 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system,
405 struct GNUNET_NETWORK_Handle *socket;
406 struct addrinfo hint;
407 struct addrinfo *ret;
409 uint32_t *port_buckets;
418 FIXME: Instead of using getaddrinfo we should try to determine the port
419 status by the following heurestics.
421 On systems which support both IPv4 and IPv6, only ports open on both
422 address families are considered open.
423 On system with either IPv4 or IPv6. A port is considered open if it's
424 open in the respective address family
426 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
427 hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM;
428 hint.ai_protocol = 0;
431 hint.ai_canonname = NULL;
433 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
434 port_buckets = (GNUNET_YES == is_tcp) ?
435 system->reserved_tcp_ports : system->reserved_udp_ports;
436 for (index = (system->lowport / 32) + 1; index < (system->highport / 32); index++)
438 xor_image = (UINT32_MAX ^ port_buckets[index]);
439 if (0 == xor_image) /* Ports in the bucket are full */
441 pos = system->lowport % 32;
444 if (0 == ((xor_image >> pos) & 1U))
449 open_port = (index * 32) + pos;
450 if (open_port >= system->highport)
452 GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
454 GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
455 GNUNET_free (open_port_str);
456 bind_status = GNUNET_NO;
457 for (ai = ret; NULL != ai; ai = ai->ai_next)
459 socket = GNUNET_NETWORK_socket_create (ai->ai_family,
460 (GNUNET_YES == is_tcp) ?
461 SOCK_STREAM : SOCK_DGRAM,
465 bind_status = GNUNET_NETWORK_socket_bind (socket,
468 GNUNET_NETWORK_socket_close (socket);
469 if (GNUNET_OK != bind_status)
472 port_buckets[index] |= (1U << pos); /* Set the port bit */
474 if (GNUNET_OK == bind_status)
476 LOG (GNUNET_ERROR_TYPE_DEBUG,
477 "Found a free port %u\n", (unsigned int) open_port);
488 * Release reservation of a TCP or UDP port for a peer
489 * (used during GNUNET_TESTING_peer_destroy).
491 * @param system system to use for reservation tracking
492 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
493 * @param port reserved port to release
496 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
500 uint32_t *port_buckets;
504 port_buckets = (GNUNET_YES == is_tcp) ?
505 system->reserved_tcp_ports : system->reserved_udp_ports;
508 LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
509 if (0 == (port_buckets[bucket] & (1U << pos)))
511 GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
514 port_buckets[bucket] &= ~(1U << pos);
519 * Testing includes a number of pre-created hostkeys for
520 * faster peer startup. This function can be used to
521 * access the n-th key of those pre-created hostkeys; note
522 * that these keys are ONLY useful for testing and not
523 * secure as the private keys are part of the public
524 * GNUnet source code.
526 * This is primarily a helper function used internally
527 * by 'GNUNET_TESTING_peer_configure'.
529 * @param system the testing system handle
530 * @param key_number desired pre-created hostkey to obtain
531 * @param id set to the peer's identity (hash of the public
532 * key; if NULL, GNUNET_SYSERR is returned immediately
533 * @return NULL on error (not enough keys)
535 struct GNUNET_CRYPTO_EccPrivateKey *
536 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
538 struct GNUNET_PeerIdentity *id)
540 struct GNUNET_CRYPTO_EccPrivateKey *private_key;
541 struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded public_key;
543 if ((NULL == id) || (NULL == system->hostkeys_data))
545 if (key_number >= system->total_hostkeys)
547 LOG (GNUNET_ERROR_TYPE_ERROR,
548 _("Key number %u does not exist\n"), key_number);
551 private_key = GNUNET_CRYPTO_ecc_decode_key (system->hostkeys_data +
553 GNUNET_TESTING_HOSTKEYFILESIZE),
554 GNUNET_TESTING_HOSTKEYFILESIZE,
556 if (NULL == private_key)
558 LOG (GNUNET_ERROR_TYPE_ERROR,
559 _("Error while decoding key %u\n"), key_number);
562 GNUNET_CRYPTO_ecc_key_get_public (private_key, &public_key);
563 GNUNET_CRYPTO_hash (&public_key,
564 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
571 * Structure for holding data to build new configurations from a configuration
577 * The system for which we are building configurations
579 struct GNUNET_TESTING_System *system;
582 * The configuration we are building
584 struct GNUNET_CONFIGURATION_Handle *cfg;
587 * The customized service home path for this peer
592 * Array of ports currently allocated to this peer. These ports will be
593 * released upon peer destroy and can be used by other peers which are
599 * The number of ports in the above array
604 * build status - to signal error while building a configuration
611 * Function to iterate over options. Copies
612 * the options to the target configuration,
613 * updating PORT values as needed.
615 * @param cls the UpdateContext
616 * @param section name of the section
617 * @param option name of the option
618 * @param value value of the option
621 update_config (void *cls, const char *section, const char *option,
624 struct UpdateContext *uc = cls;
628 char *single_variable;
629 char *per_host_variable;
630 unsigned long long num_per_host;
633 if (GNUNET_OK != uc->status)
635 if (! ((0 == strcmp (option, "PORT"))
636 || (0 == strcmp (option, "UNIXPATH"))
637 || (0 == strcmp (option, "HOSTNAME"))))
639 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
640 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
641 if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
645 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
648 /* FIXME: What about UDP? */
649 new_port = GNUNET_TESTING_reserve_port (uc->system, GNUNET_YES);
652 uc->status = GNUNET_SYSERR;
653 GNUNET_free (single_variable);
654 GNUNET_free (per_host_variable);
657 GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
659 GNUNET_array_append (uc->ports, uc->nports, new_port);
661 else if ((ival != 0) &&
663 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
665 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
669 /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
670 /* ival + ctx->fdnum % num_per_host); */
672 GNUNET_break (0); /* FIXME */
675 if (0 == strcmp (option, "UNIXPATH"))
678 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
681 GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock",
682 uc->service_home, section);
685 else if ((GNUNET_YES ==
686 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
691 GNUNET_break(0); /* FIXME */
694 if (0 == strcmp (option, "HOSTNAME"))
696 value = (NULL == uc->system->hostname) ? "localhost" : uc->system->hostname;
698 GNUNET_free (single_variable);
699 GNUNET_free (per_host_variable);
700 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
705 * Section iterator to set ACCEPT_FROM/ACCEPT_FROM6 to include the address of
706 * 'trusted_hosts' in all sections
708 * @param cls the UpdateContext
709 * @param section name of the section
712 update_config_sections (void *cls,
715 struct UpdateContext *uc = cls;
719 char *orig_allowed_hosts;
721 char *ACCEPT_FROM_key;
727 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
728 "TESTING_IGNORE_KEYS"))
732 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section,
733 "TESTING_IGNORE_KEYS", &val));
735 for (ikeys_cnt = 0; NULL != (ptr = strstr (ptr, ";")); ikeys_cnt++)
741 ikeys = GNUNET_malloc ((sizeof (char *)) * ikeys_cnt);
743 for (key = 0; key < ikeys_cnt; key++)
746 ptr = strstr (ptr, ";");
754 for (key = 0; key < ikeys_cnt; key++)
756 if (NULL != strstr (ikeys[key], "ADVERTISED_PORT"))
759 if ((key == ikeys_cnt) &&
760 (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
764 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "PORT", &ptr))
766 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section,
767 "ADVERTISED_PORT", ptr);
771 for (key = 0; key < ikeys_cnt; key++)
773 if (NULL != strstr (ikeys[key], "ACCEPT_FROM"))
782 GNUNET_free_non_null (val);
783 ACCEPT_FROM_key = "ACCEPT_FROM";
784 if ((NULL != uc->system->trusted_ip) &&
785 (NULL != strstr (uc->system->trusted_ip, ":"))) /* IPv6 in use */
786 ACCEPT_FROM_key = "ACCEPT_FROM6";
788 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, ACCEPT_FROM_key,
789 &orig_allowed_hosts))
791 orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
793 if (NULL == uc->system->trusted_ip)
794 allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
796 GNUNET_asprintf (&allowed_hosts, "%s%s;", orig_allowed_hosts,
797 uc->system->trusted_ip);
798 GNUNET_free (orig_allowed_hosts);
799 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, ACCEPT_FROM_key,
801 GNUNET_free (allowed_hosts);
806 * Create a new configuration using the given configuration as a template;
807 * ports and paths will be modified to select available ports on the local
808 * system. The default configuration will be available in PATHS section under
809 * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS
810 * section to the temporary directory specific to this configuration. If we run
811 * out of "*port" numbers, return SYSERR.
813 * This is primarily a helper function used internally
814 * by 'GNUNET_TESTING_peer_configure'.
816 * @param system system to use to coordinate resource usage
817 * @param cfg template configuration to update
818 * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
819 * be incomplete and should not be used there upon
822 GNUNET_TESTING_configuration_create_ (struct GNUNET_TESTING_System *system,
823 struct GNUNET_CONFIGURATION_Handle *cfg,
825 unsigned int *nports)
827 struct UpdateContext uc;
828 char *default_config;
832 uc.status = GNUNET_OK;
835 GNUNET_asprintf (&uc.service_home, "%s/%u", system->tmppath,
836 system->path_counter++);
837 GNUNET_asprintf (&default_config, "%s/config", uc.service_home);
838 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
840 GNUNET_CONFIGURATION_set_value_string (cfg, "arm", "CONFIG",
842 GNUNET_free (default_config);
843 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME",
845 /* make PORTs and UNIXPATHs unique */
846 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
847 /* allow connections to services from system trusted_ip host */
848 GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
849 /* enable loopback-based connections between peers */
850 GNUNET_CONFIGURATION_set_value_string (cfg,
852 "USE_LOCALADDR", "YES");
853 GNUNET_free (uc.service_home);
854 if ((NULL != ports) && (NULL != nports))
860 GNUNET_free_non_null (uc.ports);
866 * Create a new configuration using the given configuration as a template;
867 * ports and paths will be modified to select available ports on the local
868 * system. The default configuration will be available in PATHS section under
869 * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS
870 * section to the temporary directory specific to this configuration. If we run
871 * out of "*port" numbers, return SYSERR.
873 * This is primarily a helper function used internally
874 * by 'GNUNET_TESTING_peer_configure'.
876 * @param system system to use to coordinate resource usage
877 * @param cfg template configuration to update
878 * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
879 * be incomplete and should not be used there upon
882 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
883 struct GNUNET_CONFIGURATION_Handle *cfg)
885 return GNUNET_TESTING_configuration_create_ (system, cfg, NULL, NULL);
890 * Configure a GNUnet peer. GNUnet must be installed on the local
891 * system and available in the PATH.
893 * @param system system to use to coordinate resource usage
894 * @param cfg configuration to use; will be UPDATED (to reflect needed
895 * changes in port numbers and paths)
896 * @param key_number number of the hostkey to use for the peer
897 * @param id identifier for the daemon, will be set, can be NULL
898 * @param emsg set to freshly allocated error message (set to NULL on success),
900 * @return handle to the peer, NULL on error
902 struct GNUNET_TESTING_Peer *
903 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
904 struct GNUNET_CONFIGURATION_Handle *cfg,
906 struct GNUNET_PeerIdentity *id,
909 struct GNUNET_TESTING_Peer *peer;
910 struct GNUNET_DISK_FileHandle *fd;
912 char hostkey_filename[128];
913 char *config_filename;
914 char *libexec_binary;
916 struct GNUNET_CRYPTO_EccPrivateKey *pk;
924 if (GNUNET_OK != GNUNET_TESTING_configuration_create_ (system, cfg,
927 GNUNET_asprintf (&emsg_,
928 _("Failed to create configuration for peer "
929 "(not enough free ports?)\n"));
932 if (key_number >= system->total_hostkeys)
934 GNUNET_asprintf (&emsg_,
935 _("You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"),
936 (unsigned int) system->total_hostkeys);
941 (NULL == (pk = GNUNET_TESTING_hostkey_get (system, key_number, id))))
943 GNUNET_asprintf (&emsg_,
944 _("Failed to initialize hostkey for peer %u\n"),
945 (unsigned int) key_number);
949 GNUNET_CRYPTO_ecc_key_free (pk);
950 GNUNET_assert (GNUNET_OK ==
951 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
954 /* FIXME: might be better to evaluate actual configuration option here... */
955 GNUNET_snprintf (hostkey_filename, sizeof (hostkey_filename), "%s/private.ecc",
957 GNUNET_free (service_home);
958 fd = GNUNET_DISK_file_open (hostkey_filename,
959 GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
960 GNUNET_DISK_PERM_USER_READ
961 | GNUNET_DISK_PERM_USER_WRITE);
964 GNUNET_asprintf (&emsg_, _("Cannot open hostkey file: %s\n"),
968 if (GNUNET_TESTING_HOSTKEYFILESIZE !=
969 GNUNET_DISK_file_write (fd, system->hostkeys_data
970 + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE),
971 GNUNET_TESTING_HOSTKEYFILESIZE))
973 GNUNET_asprintf (&emsg_,
974 _("Failed to write hostkey file for peer %u: %s\n"),
975 (unsigned int) key_number,
977 GNUNET_DISK_file_close (fd);
980 GNUNET_DISK_file_close (fd);
981 GNUNET_assert (GNUNET_OK ==
982 GNUNET_CONFIGURATION_get_value_string
983 (cfg, "PATHS", "DEFAULTCONFIG", &config_filename));
984 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
986 GNUNET_asprintf (&emsg_,
987 _("Failed to write configuration file `%s' for peer %u: %s\n"),
989 (unsigned int) key_number,
991 GNUNET_free (config_filename);
994 peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
995 peer->cfgfile = config_filename; /* Free in peer_destroy */
996 peer->cfg = GNUNET_CONFIGURATION_dup (cfg);
997 libexec_binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
998 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "arm", "PREFIX", &peer->main_binary))
1001 GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1002 peer->args = strdup ("");
1005 peer->args = strdup (libexec_binary);
1006 peer->system = system;
1007 peer->key_number = key_number;
1008 GNUNET_free (libexec_binary);
1009 peer->ports = ports; /* Free in peer_destroy */
1010 peer->nports = nports;
1014 GNUNET_free_non_null (ports);
1015 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
1019 GNUNET_free (emsg_);
1025 * Obtain the peer identity from a peer handle.
1027 * @param peer peer handle for which we want the peer's identity
1028 * @param id identifier for the daemon, will be set
1031 GNUNET_TESTING_peer_get_identity (struct GNUNET_TESTING_Peer *peer,
1032 struct GNUNET_PeerIdentity *id)
1034 if (NULL != peer->id)
1036 memcpy (id, peer->id, sizeof (struct GNUNET_PeerIdentity));
1039 peer->id = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
1040 GNUNET_CRYPTO_ecc_key_free (GNUNET_TESTING_hostkey_get (peer->system,
1043 memcpy (id, peer->id, sizeof (struct GNUNET_PeerIdentity));
1050 * @param peer peer to start
1051 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
1054 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
1056 if (NULL != peer->main_process)
1059 return GNUNET_SYSERR;
1061 GNUNET_assert (NULL != peer->cfgfile);
1062 peer->main_process = GNUNET_OS_start_process (PIPE_CONTROL,
1063 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
1071 if (NULL == peer->main_process)
1073 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1074 _("Failed to start `%s': %s\n"),
1077 return GNUNET_SYSERR;
1084 * Start a service at a peer using its ARM service
1086 * @param peer the peer whose service has to be started
1087 * @param service_name name of the service to start
1088 * @param timeout how long should the ARM API try to send the request to start
1090 * @param cont the callback to call with result and status from ARM API
1091 * @param cont_cls the closure for the above callback
1092 * @return GNUNET_OK upon successfully queuing the service start request;
1093 * GNUNET_SYSERR upon error
1096 GNUNET_TESTING_peer_service_start (struct GNUNET_TESTING_Peer *peer,
1097 const char *service_name,
1098 struct GNUNET_TIME_Relative timeout,
1099 GNUNET_ARM_ResultCallback cont,
1102 if (NULL == peer->ah)
1103 return GNUNET_SYSERR;
1104 GNUNET_ARM_request_service_start (peer->ah,
1106 GNUNET_OS_INHERIT_STD_ALL,
1114 * Stop a service at a peer using its ARM service
1116 * @param peer the peer whose service has to be stopped
1117 * @param service_name name of the service to stop
1118 * @param timeout how long should the ARM API try to send the request to stop
1120 * @param cont the callback to call with result and status from ARM API
1121 * @param cont_cls the closure for the above callback
1122 * @return GNUNET_OK upon successfully queuing the service stop request;
1123 * GNUNET_SYSERR upon error
1126 GNUNET_TESTING_peer_service_stop (struct GNUNET_TESTING_Peer *peer,
1127 const char *service_name,
1128 struct GNUNET_TIME_Relative timeout,
1129 GNUNET_ARM_ResultCallback cont,
1132 if (NULL == peer->ah)
1133 return GNUNET_SYSERR;
1134 GNUNET_ARM_request_service_stop (peer->ah,
1143 * Sends SIGTERM to the peer's main process
1145 * @param peer the handle to the peer
1146 * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1147 * or upon any error while sending SIGTERM
1150 GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer)
1152 if (NULL == peer->main_process)
1155 return GNUNET_SYSERR;
1157 return (0 == GNUNET_OS_process_kill (peer->main_process, SIGTERM)) ?
1158 GNUNET_OK : GNUNET_SYSERR;
1163 * Waits for a peer to terminate. The peer's main process will also be destroyed.
1165 * @param peer the handle to the peer
1166 * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1167 * or upon any error while waiting
1170 GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer)
1174 if (NULL == peer->main_process)
1177 return GNUNET_SYSERR;
1179 ret = GNUNET_OS_process_wait (peer->main_process);
1180 GNUNET_OS_process_destroy (peer->main_process);
1181 peer->main_process = NULL;
1189 * @param peer peer to stop
1190 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1193 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
1195 if (GNUNET_SYSERR == GNUNET_TESTING_peer_kill (peer))
1196 return GNUNET_SYSERR;
1197 if (GNUNET_SYSERR == GNUNET_TESTING_peer_wait (peer))
1198 return GNUNET_SYSERR;
1204 * Function called whenever we connect to or disconnect from ARM.
1206 * @param cls closure
1207 * @param arm handle to the ARM connection
1208 * @param connected GNUNET_YES if connected, GNUNET_NO if disconnected,
1209 * GNUNET_SYSERR on error.
1212 disconn_status (void *cls, struct GNUNET_ARM_Handle *arm,
1215 struct GNUNET_TESTING_Peer *peer = cls;
1217 if (GNUNET_SYSERR == connected)
1219 peer->cb (peer->cb_cls, peer, connected);
1222 if (GNUNET_YES == connected)
1224 GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_kill (peer));
1227 GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_wait (peer));
1228 GNUNET_ARM_disconnect_and_free (peer->ah);
1230 peer->cb (peer->cb_cls, peer, GNUNET_YES);
1235 * Stop a peer asynchronously using ARM API. Peer's shutdown is signaled
1236 * through the GNUNET_TESTING_PeerStopCallback().
1238 * @param peer the peer to stop
1239 * @param cb the callback to signal peer shutdown
1240 * @param cb_cls closure for the above callback
1241 * @return GNUNET_OK upon successfully giving the request to the ARM API (this
1242 * does not mean that the peer is successfully stopped); GNUNET_SYSERR
1246 GNUNET_TESTING_peer_stop_async (struct GNUNET_TESTING_Peer *peer,
1247 GNUNET_TESTING_PeerStopCallback cb,
1250 if (NULL == peer->main_process)
1251 return GNUNET_SYSERR;
1252 peer->ah = GNUNET_ARM_connect (peer->cfg, &disconn_status, peer);
1253 if (NULL == peer->ah)
1254 return GNUNET_SYSERR;
1256 peer->cb_cls = cb_cls;
1262 * Destroy the peer. Releases resources locked during peer configuration.
1263 * If the peer is still running, it will be stopped AND a warning will be
1264 * printed (users of the API should stop the peer explicitly first).
1266 * @param peer peer to destroy
1269 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
1273 if (NULL != peer->main_process)
1274 GNUNET_TESTING_peer_stop (peer);
1275 if (NULL != peer->ah)
1276 GNUNET_ARM_disconnect_and_free (peer->ah);
1277 if (NULL != peer->mh)
1278 GNUNET_ARM_monitor_disconnect_and_free (peer->mh);
1279 GNUNET_free (peer->cfgfile);
1280 if (NULL != peer->cfg)
1281 GNUNET_CONFIGURATION_destroy (peer->cfg);
1282 GNUNET_free (peer->main_binary);
1283 GNUNET_free (peer->args);
1284 GNUNET_free_non_null (peer->id);
1285 if (NULL != peer->ports)
1287 for (cnt = 0; cnt < peer->nports; cnt++)
1288 GNUNET_TESTING_release_port (peer->system,
1291 GNUNET_free (peer->ports);
1298 * Start a single peer and run a test using the testing library.
1299 * Starts a peer using the given configuration and then invokes the
1300 * given callback. This function ALSO initializes the scheduler loop
1301 * and should thus be called directly from "main". The testcase
1302 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1304 * @param testdir only the directory name without any path. This is used for
1305 * all service homes; the directory will be created in a temporary
1306 * location depending on the underlying OS
1307 * @param cfgfilename name of the configuration file to use;
1308 * use NULL to only run with defaults
1309 * @param tm main function of the testcase
1310 * @param tm_cls closure for 'tm'
1311 * @return 0 on success, 1 on error
1314 GNUNET_TESTING_peer_run (const char *testdir,
1315 const char *cfgfilename,
1316 GNUNET_TESTING_TestMain tm,
1319 return GNUNET_TESTING_service_run (testdir, "arm",
1320 cfgfilename, tm, tm_cls);
1325 * Structure for holding service data
1327 struct ServiceContext
1330 * The configuration of the peer in which the service is run
1332 const struct GNUNET_CONFIGURATION_Handle *cfg;
1335 * Callback to signal service startup
1337 GNUNET_TESTING_TestMain tm;
1340 * The peer in which the service is run.
1342 struct GNUNET_TESTING_Peer *peer;
1345 * Closure for the above callback
1352 * Callback to be called when SCHEDULER has been started
1354 * @param cls the ServiceContext
1355 * @param tc the TaskContext
1358 service_run_main (void *cls,
1359 const struct GNUNET_SCHEDULER_TaskContext *tc)
1361 struct ServiceContext *sc = cls;
1363 sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1368 * Start a single service (no ARM, except of course if the given
1369 * service name is 'arm') and run a test using the testing library.
1370 * Starts a service using the given configuration and then invokes the
1371 * given callback. This function ALSO initializes the scheduler loop
1372 * and should thus be called directly from "main". The testcase
1373 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1375 * This function is useful if the testcase is for a single service
1376 * and if that service doesn't itself depend on other services.
1378 * @param testdir only the directory name without any path. This is used for
1379 * all service homes; the directory will be created in a temporary
1380 * location depending on the underlying OS
1381 * @param service_name name of the service to run
1382 * @param cfgfilename name of the configuration file to use;
1383 * use NULL to only run with defaults
1384 * @param tm main function of the testcase
1385 * @param tm_cls closure for 'tm'
1386 * @return 0 on success, 1 on error
1389 GNUNET_TESTING_service_run (const char *testdir,
1390 const char *service_name,
1391 const char *cfgfilename,
1392 GNUNET_TESTING_TestMain tm,
1395 struct ServiceContext sc;
1396 struct GNUNET_TESTING_System *system;
1397 struct GNUNET_TESTING_Peer *peer;
1398 struct GNUNET_CONFIGURATION_Handle *cfg;
1400 char *libexec_binary;
1402 GNUNET_log_setup (testdir, "WARNING", NULL);
1403 system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL);
1406 cfg = GNUNET_CONFIGURATION_create ();
1407 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1409 LOG (GNUNET_ERROR_TYPE_ERROR,
1410 _("Failed to load configuration from %s\n"), cfgfilename);
1411 GNUNET_CONFIGURATION_destroy (cfg);
1412 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1415 peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1418 GNUNET_CONFIGURATION_destroy (cfg);
1419 hostkeys_unload (system);
1420 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1423 GNUNET_free (peer->main_binary);
1424 GNUNET_free (peer->args);
1425 GNUNET_asprintf (&binary, "gnunet-service-%s", service_name);
1426 libexec_binary = GNUNET_OS_get_libexec_binary_path (binary);
1427 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, service_name, "PREFIX", &peer->main_binary))
1430 GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1431 peer->args = strdup ("");
1434 peer->args = strdup (libexec_binary);
1436 GNUNET_free (libexec_binary);
1437 GNUNET_free (binary);
1438 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1440 GNUNET_TESTING_peer_destroy (peer);
1441 GNUNET_CONFIGURATION_destroy (cfg);
1442 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1449 GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1450 if ((NULL != peer->main_process) &&
1451 (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1453 GNUNET_TESTING_peer_destroy (peer);
1454 GNUNET_CONFIGURATION_destroy (cfg);
1455 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1458 GNUNET_TESTING_peer_destroy (peer);
1459 GNUNET_CONFIGURATION_destroy (cfg);
1460 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1466 * Sometimes we use the binary name to determine which specific
1467 * test to run. In those cases, the string after the last "_"
1468 * in 'argv[0]' specifies a string that determines the configuration
1469 * file or plugin to use.
1471 * This function returns the respective substring, taking care
1472 * of issues such as binaries ending in '.exe' on W32.
1474 * @param argv0 the name of the binary
1475 * @return string between the last '_' and the '.exe' (or the end of the string),
1476 * NULL if argv0 has no '_'
1479 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1481 size_t slen = strlen (argv0) + 1;
1486 memcpy (sbuf, argv0, slen);
1487 ret = strrchr (sbuf, '_');
1490 ret++; /* skip underscore */
1491 dot = strchr (ret, '.');
1494 return GNUNET_strdup (ret);
1498 /* end of testing.c */