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 * memory map for 'hostkeys_data'.
97 struct GNUNET_DISK_MapHandle *map;
100 * Bitmap where each TCP port that has already been reserved for
101 * some GNUnet peer is recorded. Note that we additionally need to
102 * test if a port is already in use by non-GNUnet components before
103 * assigning it to a peer/service. If we detect that a port is
104 * already in use, we also mark it in this bitmap. So all the bits
105 * that are zero merely indicate ports that MIGHT be available for
108 uint32_t reserved_tcp_ports[65536 / 32];
111 * Bitmap where each UDP port that has already been reserved for
112 * some GNUnet peer is recorded. Note that we additionally need to
113 * test if a port is already in use by non-GNUnet components before
114 * assigning it to a peer/service. If we detect that a port is
115 * already in use, we also mark it in this bitmap. So all the bits
116 * that are zero merely indicate ports that MIGHT be available for
119 uint32_t reserved_udp_ports[65536 / 32];
122 * Counter we use to make service home paths unique on this system;
123 * the full path consists of the tmppath and this number. Each
124 * UNIXPATH for a peer is also modified to include the respective
125 * path counter to ensure uniqueness. This field is incremented
126 * by one for each configured peer. Even if peers are destroyed,
127 * we never re-use path counters.
129 uint32_t path_counter;
132 * The number of hostkeys
134 uint32_t total_hostkeys;
137 * Lowest port we are allowed to use.
142 * Highest port we are allowed to use.
149 * Handle for a GNUnet peer controlled by testing.
151 struct GNUNET_TESTING_Peer
154 * The TESTING system associated with this peer
156 struct GNUNET_TESTING_System *system;
159 * Path to the configuration file for this peer.
164 * Binary to be executed during 'GNUNET_TESTING_peer_start'.
165 * Typically 'gnunet-service-arm' (but can be set to a
166 * specific service by 'GNUNET_TESTING_service_run' if
173 * Handle to the running binary of the service, NULL if the
174 * peer/service is currently not running.
176 struct GNUNET_OS_Process *main_process;
179 * The handle to the peer's ARM service
181 struct GNUNET_ARM_Handle *ah;
184 * Handle to ARM monitoring
186 struct GNUNET_ARM_MonitorHandle *mh;
189 * The config of the peer
191 struct GNUNET_CONFIGURATION_Handle *cfg;
194 * The callback to call asynchronously when a peer is stopped
196 GNUNET_TESTING_PeerStopCallback cb;
199 * The closure for the above callback
204 * The cached identity of this peer. Will be populated on call to
205 * GNUNET_TESTING_peer_get_identity()
207 struct GNUNET_PeerIdentity *id;
210 * Array of ports currently allocated to this peer. These ports will be
211 * released upon peer destroy and can be used by other peers which are
217 * The number of ports in the above array
222 * The keynumber of this peer's hostkey
229 * Testing includes a number of pre-created hostkeys for faster peer
230 * startup. This function loads such keys into memory from a file.
232 * @param system the testing system handle
233 * @return GNUNET_OK on success; GNUNET_SYSERR on error
236 hostkeys_load (struct GNUNET_TESTING_System *system)
241 struct GNUNET_DISK_FileHandle *fd;
243 GNUNET_assert (NULL == system->hostkeys_data);
244 data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
245 GNUNET_asprintf (&filename, "%s/testing_hostkeys.ecc", data_dir);
246 GNUNET_free (data_dir);
248 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
250 LOG (GNUNET_ERROR_TYPE_ERROR,
251 _("Hostkeys file not found: %s\n"), filename);
252 GNUNET_free (filename);
253 return GNUNET_SYSERR;
255 /* Check hostkey file size, read entire thing into memory */
257 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
261 GNUNET_free (filename);
262 return GNUNET_SYSERR; /* File is empty */
264 if (0 != (fs % GNUNET_TESTING_HOSTKEYFILESIZE))
266 LOG (GNUNET_ERROR_TYPE_ERROR,
267 _("Incorrect hostkey file format: %s\n"), filename);
268 GNUNET_free (filename);
269 return GNUNET_SYSERR;
271 fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
272 GNUNET_DISK_PERM_NONE);
275 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename);
276 GNUNET_free (filename);
277 return GNUNET_SYSERR;
279 GNUNET_free (filename);
280 system->hostkeys_data = GNUNET_DISK_file_map (fd,
282 GNUNET_DISK_MAP_TYPE_READ,
284 GNUNET_DISK_file_close (fd);
285 if (NULL == system->hostkeys_data)
286 return GNUNET_SYSERR;
287 system->total_hostkeys = fs / GNUNET_TESTING_HOSTKEYFILESIZE;
293 * Function to remove the loaded hostkeys
295 * @param system the testing system handle
298 hostkeys_unload (struct GNUNET_TESTING_System *system)
300 GNUNET_break (NULL != system->hostkeys_data);
301 system->hostkeys_data = NULL;
302 GNUNET_DISK_file_unmap (system->map);
304 system->hostkeys_data = NULL;
305 system->total_hostkeys = 0;
310 * Create a system handle. There must only be one system
311 * handle per operating system.
313 * @param testdir only the directory name without any path. This is used for
314 * all service homes; the directory will be created in a temporary
315 * location depending on the underlying OS
316 * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
317 * service configurations generated to allow control connections from
318 * this ip. This can either be a single ip address or a network address
320 * @param hostname the hostname of the system we are using for testing; NULL for
322 * @param lowport lowest port number this system is allowed to allocate (inclusive)
323 * @param highport highest port number this system is allowed to allocate (exclusive)
324 * @return handle to this system, NULL on error
326 struct GNUNET_TESTING_System *
327 GNUNET_TESTING_system_create_with_portrange (const char *testdir,
328 const char *trusted_ip,
329 const char *hostname,
333 struct GNUNET_TESTING_System *system;
335 GNUNET_assert (NULL != testdir);
336 system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
337 system->tmppath = GNUNET_DISK_mkdtemp (testdir);
338 system->lowport = lowport;
339 system->highport = highport;
340 if (NULL == system->tmppath)
342 GNUNET_free (system);
345 if (NULL != trusted_ip)
346 system->trusted_ip = GNUNET_strdup (trusted_ip);
347 if (NULL != hostname)
348 system->hostname = GNUNET_strdup (hostname);
349 if (GNUNET_OK != hostkeys_load (system))
351 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
359 * Create a system handle. There must only be one system handle per operating
360 * system. Uses a default range for allowed ports. Ports are still tested for
363 * @param testdir only the directory name without any path. This is used for all
364 * service homes; the directory will be created in a temporary location
365 * depending on the underlying OS
366 * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
367 * service configurations generated to allow control connections from
368 * this ip. This can either be a single ip address or a network address
370 * @param hostname the hostname of the system we are using for testing; NULL for
372 * @return handle to this system, NULL on error
374 struct GNUNET_TESTING_System *
375 GNUNET_TESTING_system_create (const char *testdir,
376 const char *trusted_ip,
377 const char *hostname)
379 return GNUNET_TESTING_system_create_with_portrange (testdir,
388 * Free system resources.
390 * @param system system to be freed
391 * @param remove_paths should the 'testdir' and all subdirectories
392 * be removed (clean up on shutdown)?
395 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
398 if (NULL != system->hostkeys_data)
399 hostkeys_unload (system);
400 if (GNUNET_YES == remove_paths)
401 GNUNET_DISK_directory_remove (system->tmppath);
402 GNUNET_free (system->tmppath);
403 GNUNET_free_non_null (system->trusted_ip);
404 GNUNET_free_non_null (system->hostname);
405 GNUNET_free (system);
410 * Reserve a TCP or UDP port for a peer.
412 * @param system system to use for reservation tracking
413 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
414 * @return 0 if no free port was available
417 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system,
420 struct GNUNET_NETWORK_Handle *socket;
421 struct addrinfo hint;
422 struct addrinfo *ret;
424 uint32_t *port_buckets;
433 FIXME: Instead of using getaddrinfo we should try to determine the port
434 status by the following heurestics.
436 On systems which support both IPv4 and IPv6, only ports open on both
437 address families are considered open.
438 On system with either IPv4 or IPv6. A port is considered open if it's
439 open in the respective address family
441 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
442 hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM;
443 hint.ai_protocol = 0;
446 hint.ai_canonname = NULL;
448 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
449 port_buckets = (GNUNET_YES == is_tcp) ?
450 system->reserved_tcp_ports : system->reserved_udp_ports;
451 for (index = (system->lowport / 32) + 1; index < (system->highport / 32); index++)
453 xor_image = (UINT32_MAX ^ port_buckets[index]);
454 if (0 == xor_image) /* Ports in the bucket are full */
456 pos = system->lowport % 32;
459 if (0 == ((xor_image >> pos) & 1U))
464 open_port = (index * 32) + pos;
465 if (open_port >= system->highport)
467 GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
469 GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
470 GNUNET_free (open_port_str);
471 bind_status = GNUNET_NO;
472 for (ai = ret; NULL != ai; ai = ai->ai_next)
474 socket = GNUNET_NETWORK_socket_create (ai->ai_family,
475 (GNUNET_YES == is_tcp) ?
476 SOCK_STREAM : SOCK_DGRAM,
480 bind_status = GNUNET_NETWORK_socket_bind (socket,
483 GNUNET_NETWORK_socket_close (socket);
484 if (GNUNET_OK != bind_status)
487 port_buckets[index] |= (1U << pos); /* Set the port bit */
489 if (GNUNET_OK == bind_status)
491 LOG (GNUNET_ERROR_TYPE_DEBUG,
492 "Found a free port %u\n", (unsigned int) open_port);
503 * Release reservation of a TCP or UDP port for a peer
504 * (used during GNUNET_TESTING_peer_destroy).
506 * @param system system to use for reservation tracking
507 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
508 * @param port reserved port to release
511 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
515 uint32_t *port_buckets;
519 port_buckets = (GNUNET_YES == is_tcp) ?
520 system->reserved_tcp_ports : system->reserved_udp_ports;
523 LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
524 if (0 == (port_buckets[bucket] & (1U << pos)))
526 GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
529 port_buckets[bucket] &= ~(1U << pos);
534 * Testing includes a number of pre-created hostkeys for
535 * faster peer startup. This function can be used to
536 * access the n-th key of those pre-created hostkeys; note
537 * that these keys are ONLY useful for testing and not
538 * secure as the private keys are part of the public
539 * GNUnet source code.
541 * This is primarily a helper function used internally
542 * by 'GNUNET_TESTING_peer_configure'.
544 * @param system the testing system handle
545 * @param key_number desired pre-created hostkey to obtain
546 * @param id set to the peer's identity (hash of the public
547 * key; if NULL, GNUNET_SYSERR is returned immediately
548 * @return NULL on error (not enough keys)
550 struct GNUNET_CRYPTO_EccPrivateKey *
551 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
553 struct GNUNET_PeerIdentity *id)
555 struct GNUNET_CRYPTO_EccPrivateKey *private_key;
556 struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded public_key;
558 if ((NULL == id) || (NULL == system->hostkeys_data))
560 if (key_number >= system->total_hostkeys)
562 LOG (GNUNET_ERROR_TYPE_ERROR,
563 _("Key number %u does not exist\n"), key_number);
566 private_key = GNUNET_CRYPTO_ecc_decode_key (system->hostkeys_data +
568 GNUNET_TESTING_HOSTKEYFILESIZE),
569 GNUNET_TESTING_HOSTKEYFILESIZE,
571 if (NULL == private_key)
573 LOG (GNUNET_ERROR_TYPE_ERROR,
574 _("Error while decoding key %u\n"), key_number);
577 GNUNET_CRYPTO_ecc_key_get_public (private_key, &public_key);
578 GNUNET_CRYPTO_hash (&public_key,
579 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
586 * Structure for holding data to build new configurations from a configuration
592 * The system for which we are building configurations
594 struct GNUNET_TESTING_System *system;
597 * The configuration we are building
599 struct GNUNET_CONFIGURATION_Handle *cfg;
602 * The customized service home path for this peer
607 * Array of ports currently allocated to this peer. These ports will be
608 * released upon peer destroy and can be used by other peers which are
614 * The number of ports in the above array
619 * build status - to signal error while building a configuration
626 * Function to iterate over options. Copies
627 * the options to the target configuration,
628 * updating PORT values as needed.
630 * @param cls the UpdateContext
631 * @param section name of the section
632 * @param option name of the option
633 * @param value value of the option
636 update_config (void *cls, const char *section, const char *option,
639 struct UpdateContext *uc = cls;
643 char *single_variable;
644 char *per_host_variable;
645 unsigned long long num_per_host;
648 if (GNUNET_OK != uc->status)
650 if (! ((0 == strcmp (option, "PORT"))
651 || (0 == strcmp (option, "UNIXPATH"))
652 || (0 == strcmp (option, "HOSTNAME"))))
654 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
655 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
656 if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
660 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
663 /* FIXME: What about UDP? */
664 new_port = GNUNET_TESTING_reserve_port (uc->system, GNUNET_YES);
667 uc->status = GNUNET_SYSERR;
668 GNUNET_free (single_variable);
669 GNUNET_free (per_host_variable);
672 GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
674 GNUNET_array_append (uc->ports, uc->nports, new_port);
676 else if ((ival != 0) &&
678 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
680 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
684 /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
685 /* ival + ctx->fdnum % num_per_host); */
687 GNUNET_break (0); /* FIXME */
690 if (0 == strcmp (option, "UNIXPATH"))
693 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
696 GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock",
697 uc->service_home, section);
700 else if ((GNUNET_YES ==
701 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
706 GNUNET_break(0); /* FIXME */
709 if (0 == strcmp (option, "HOSTNAME"))
711 value = (NULL == uc->system->hostname) ? "localhost" : uc->system->hostname;
713 GNUNET_free (single_variable);
714 GNUNET_free (per_host_variable);
715 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
720 * Section iterator to set ACCEPT_FROM/ACCEPT_FROM6 to include the address of
721 * 'trusted_hosts' in all sections
723 * @param cls the UpdateContext
724 * @param section name of the section
727 update_config_sections (void *cls,
730 struct UpdateContext *uc = cls;
734 char *orig_allowed_hosts;
736 char *ACCEPT_FROM_key;
742 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
743 "TESTING_IGNORE_KEYS"))
747 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section,
748 "TESTING_IGNORE_KEYS", &val));
750 for (ikeys_cnt = 0; NULL != (ptr = strstr (ptr, ";")); ikeys_cnt++)
756 ikeys = GNUNET_malloc ((sizeof (char *)) * ikeys_cnt);
758 for (key = 0; key < ikeys_cnt; key++)
761 ptr = strstr (ptr, ";");
769 for (key = 0; key < ikeys_cnt; key++)
771 if (NULL != strstr (ikeys[key], "ADVERTISED_PORT"))
774 if ((key == ikeys_cnt) &&
775 (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
779 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "PORT", &ptr))
781 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section,
782 "ADVERTISED_PORT", ptr);
786 for (key = 0; key < ikeys_cnt; key++)
788 if (NULL != strstr (ikeys[key], "ACCEPT_FROM"))
797 GNUNET_free_non_null (val);
798 ACCEPT_FROM_key = "ACCEPT_FROM";
799 if ((NULL != uc->system->trusted_ip) &&
800 (NULL != strstr (uc->system->trusted_ip, ":"))) /* IPv6 in use */
801 ACCEPT_FROM_key = "ACCEPT_FROM6";
803 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, ACCEPT_FROM_key,
804 &orig_allowed_hosts))
806 orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
808 if (NULL == uc->system->trusted_ip)
809 allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
811 GNUNET_asprintf (&allowed_hosts, "%s%s;", orig_allowed_hosts,
812 uc->system->trusted_ip);
813 GNUNET_free (orig_allowed_hosts);
814 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, ACCEPT_FROM_key,
816 GNUNET_free (allowed_hosts);
821 * Create a new configuration using the given configuration as a template;
822 * ports and paths will be modified to select available ports on the local
823 * system. The default configuration will be available in PATHS section under
824 * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS
825 * section to the temporary directory specific to this configuration. If we run
826 * out of "*port" numbers, return SYSERR.
828 * This is primarily a helper function used internally
829 * by 'GNUNET_TESTING_peer_configure'.
831 * @param system system to use to coordinate resource usage
832 * @param cfg template configuration to update
833 * @param ports array with port numbers used in the created configuration.
834 * Will be updated upon successful return. Can be NULL
835 * @param nports the size of the `ports' array. Will be updated.
836 * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
837 * be incomplete and should not be used there upon
840 GNUNET_TESTING_configuration_create_ (struct GNUNET_TESTING_System *system,
841 struct GNUNET_CONFIGURATION_Handle *cfg,
843 unsigned int *nports)
845 struct UpdateContext uc;
846 char *default_config;
850 uc.status = GNUNET_OK;
853 GNUNET_asprintf (&uc.service_home, "%s/%u", system->tmppath,
854 system->path_counter++);
855 GNUNET_asprintf (&default_config, "%s/config", uc.service_home);
856 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
858 GNUNET_CONFIGURATION_set_value_string (cfg, "arm", "CONFIG",
860 GNUNET_free (default_config);
861 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME",
863 /* make PORTs and UNIXPATHs unique */
864 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
865 /* allow connections to services from system trusted_ip host */
866 GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
867 /* enable loopback-based connections between peers */
868 GNUNET_CONFIGURATION_set_value_string (cfg,
870 "USE_LOCALADDR", "YES");
871 GNUNET_free (uc.service_home);
872 if ((NULL != ports) && (NULL != nports))
878 GNUNET_free_non_null (uc.ports);
884 * Create a new configuration using the given configuration as a template;
885 * ports and paths will be modified to select available ports on the local
886 * system. The default configuration will be available in PATHS section under
887 * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS
888 * section to the temporary directory specific to this configuration. If we run
889 * out of "*port" numbers, return SYSERR.
891 * This is primarily a helper function used internally
892 * by 'GNUNET_TESTING_peer_configure'.
894 * @param system system to use to coordinate resource usage
895 * @param cfg template configuration to update
896 * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
897 * be incomplete and should not be used there upon
900 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
901 struct GNUNET_CONFIGURATION_Handle *cfg)
903 return GNUNET_TESTING_configuration_create_ (system, cfg, NULL, NULL);
908 * Configure a GNUnet peer. GNUnet must be installed on the local
909 * system and available in the PATH.
911 * @param system system to use to coordinate resource usage
912 * @param cfg configuration to use; will be UPDATED (to reflect needed
913 * changes in port numbers and paths)
914 * @param key_number number of the hostkey to use for the peer
915 * @param id identifier for the daemon, will be set, can be NULL
916 * @param emsg set to freshly allocated error message (set to NULL on success),
918 * @return handle to the peer, NULL on error
920 struct GNUNET_TESTING_Peer *
921 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
922 struct GNUNET_CONFIGURATION_Handle *cfg,
924 struct GNUNET_PeerIdentity *id,
927 struct GNUNET_TESTING_Peer *peer;
928 struct GNUNET_DISK_FileHandle *fd;
930 char hostkey_filename[128];
931 char *config_filename;
932 char *libexec_binary;
934 struct GNUNET_CRYPTO_EccPrivateKey *pk;
942 if (GNUNET_OK != GNUNET_TESTING_configuration_create_ (system, cfg,
945 GNUNET_asprintf (&emsg_,
946 _("Failed to create configuration for peer "
947 "(not enough free ports?)\n"));
950 if (key_number >= system->total_hostkeys)
952 GNUNET_asprintf (&emsg_,
953 _("You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"),
954 (unsigned int) system->total_hostkeys);
959 (NULL == (pk = GNUNET_TESTING_hostkey_get (system, key_number, id))))
961 GNUNET_asprintf (&emsg_,
962 _("Failed to initialize hostkey for peer %u\n"),
963 (unsigned int) key_number);
967 GNUNET_CRYPTO_ecc_key_free (pk);
968 GNUNET_assert (GNUNET_OK ==
969 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
972 /* FIXME: might be better to evaluate actual configuration option here... */
973 GNUNET_snprintf (hostkey_filename, sizeof (hostkey_filename), "%s/private.ecc",
975 GNUNET_free (service_home);
976 fd = GNUNET_DISK_file_open (hostkey_filename,
977 GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
978 GNUNET_DISK_PERM_USER_READ
979 | GNUNET_DISK_PERM_USER_WRITE);
982 GNUNET_asprintf (&emsg_, _("Cannot open hostkey file: %s\n"),
986 if (GNUNET_TESTING_HOSTKEYFILESIZE !=
987 GNUNET_DISK_file_write (fd, system->hostkeys_data
988 + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE),
989 GNUNET_TESTING_HOSTKEYFILESIZE))
991 GNUNET_asprintf (&emsg_,
992 _("Failed to write hostkey file for peer %u: %s\n"),
993 (unsigned int) key_number,
995 GNUNET_DISK_file_close (fd);
998 GNUNET_DISK_file_close (fd);
999 GNUNET_assert (GNUNET_OK ==
1000 GNUNET_CONFIGURATION_get_value_string
1001 (cfg, "PATHS", "DEFAULTCONFIG", &config_filename));
1002 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
1004 GNUNET_asprintf (&emsg_,
1005 _("Failed to write configuration file `%s' for peer %u: %s\n"),
1007 (unsigned int) key_number,
1009 GNUNET_free (config_filename);
1012 peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
1013 peer->cfgfile = config_filename; /* Free in peer_destroy */
1014 peer->cfg = GNUNET_CONFIGURATION_dup (cfg);
1015 libexec_binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
1016 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "arm", "PREFIX", &peer->main_binary))
1019 GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1020 peer->args = strdup ("");
1023 peer->args = strdup (libexec_binary);
1024 peer->system = system;
1025 peer->key_number = key_number;
1026 GNUNET_free (libexec_binary);
1027 peer->ports = ports; /* Free in peer_destroy */
1028 peer->nports = nports;
1032 GNUNET_free_non_null (ports);
1033 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
1037 GNUNET_free (emsg_);
1043 * Obtain the peer identity from a peer handle.
1045 * @param peer peer handle for which we want the peer's identity
1046 * @param id identifier for the daemon, will be set
1049 GNUNET_TESTING_peer_get_identity (struct GNUNET_TESTING_Peer *peer,
1050 struct GNUNET_PeerIdentity *id)
1052 if (NULL != peer->id)
1054 memcpy (id, peer->id, sizeof (struct GNUNET_PeerIdentity));
1057 peer->id = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
1058 GNUNET_CRYPTO_ecc_key_free (GNUNET_TESTING_hostkey_get (peer->system,
1061 memcpy (id, peer->id, sizeof (struct GNUNET_PeerIdentity));
1068 * @param peer peer to start
1069 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
1072 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
1074 if (NULL != peer->main_process)
1077 return GNUNET_SYSERR;
1079 GNUNET_assert (NULL != peer->cfgfile);
1080 peer->main_process = GNUNET_OS_start_process (PIPE_CONTROL,
1081 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
1089 if (NULL == peer->main_process)
1091 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1092 _("Failed to start `%s': %s\n"),
1095 return GNUNET_SYSERR;
1102 * Start a service at a peer using its ARM service
1104 * @param peer the peer whose service has to be started
1105 * @param service_name name of the service to start
1106 * @param timeout how long should the ARM API try to send the request to start
1108 * @param cont the callback to call with result and status from ARM API
1109 * @param cont_cls the closure for the above callback
1110 * @return GNUNET_OK upon successfully queuing the service start request;
1111 * GNUNET_SYSERR upon error
1114 GNUNET_TESTING_peer_service_start (struct GNUNET_TESTING_Peer *peer,
1115 const char *service_name,
1116 struct GNUNET_TIME_Relative timeout,
1117 GNUNET_ARM_ResultCallback cont,
1120 if (NULL == peer->ah)
1121 return GNUNET_SYSERR;
1122 GNUNET_ARM_request_service_start (peer->ah,
1124 GNUNET_OS_INHERIT_STD_ALL,
1132 * Stop a service at a peer using its ARM service
1134 * @param peer the peer whose service has to be stopped
1135 * @param service_name name of the service to stop
1136 * @param timeout how long should the ARM API try to send the request to stop
1138 * @param cont the callback to call with result and status from ARM API
1139 * @param cont_cls the closure for the above callback
1140 * @return GNUNET_OK upon successfully queuing the service stop request;
1141 * GNUNET_SYSERR upon error
1144 GNUNET_TESTING_peer_service_stop (struct GNUNET_TESTING_Peer *peer,
1145 const char *service_name,
1146 struct GNUNET_TIME_Relative timeout,
1147 GNUNET_ARM_ResultCallback cont,
1150 if (NULL == peer->ah)
1151 return GNUNET_SYSERR;
1152 GNUNET_ARM_request_service_stop (peer->ah,
1161 * Sends SIGTERM to the peer's main process
1163 * @param peer the handle to the peer
1164 * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1165 * or upon any error while sending SIGTERM
1168 GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer)
1170 if (NULL == peer->main_process)
1173 return GNUNET_SYSERR;
1175 return (0 == GNUNET_OS_process_kill (peer->main_process, SIGTERM)) ?
1176 GNUNET_OK : GNUNET_SYSERR;
1181 * Waits for a peer to terminate. The peer's main process will also be destroyed.
1183 * @param peer the handle to the peer
1184 * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1185 * or upon any error while waiting
1188 GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer)
1192 if (NULL == peer->main_process)
1195 return GNUNET_SYSERR;
1197 ret = GNUNET_OS_process_wait (peer->main_process);
1198 GNUNET_OS_process_destroy (peer->main_process);
1199 peer->main_process = NULL;
1207 * @param peer peer to stop
1208 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1211 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
1213 if (GNUNET_SYSERR == GNUNET_TESTING_peer_kill (peer))
1214 return GNUNET_SYSERR;
1215 if (GNUNET_SYSERR == GNUNET_TESTING_peer_wait (peer))
1216 return GNUNET_SYSERR;
1222 * Function called whenever we connect to or disconnect from ARM.
1224 * @param cls closure
1225 * @param connected GNUNET_YES if connected, GNUNET_NO if disconnected,
1226 * GNUNET_SYSERR on error.
1229 disconn_status (void *cls,
1232 struct GNUNET_TESTING_Peer *peer = cls;
1234 if (GNUNET_SYSERR == connected)
1236 peer->cb (peer->cb_cls, peer, connected);
1239 if (GNUNET_YES == connected)
1241 GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_kill (peer));
1244 GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_wait (peer));
1245 GNUNET_ARM_disconnect_and_free (peer->ah);
1247 peer->cb (peer->cb_cls, peer, GNUNET_YES);
1252 * Stop a peer asynchronously using ARM API. Peer's shutdown is signaled
1253 * through the GNUNET_TESTING_PeerStopCallback().
1255 * @param peer the peer to stop
1256 * @param cb the callback to signal peer shutdown
1257 * @param cb_cls closure for the above callback
1258 * @return GNUNET_OK upon successfully giving the request to the ARM API (this
1259 * does not mean that the peer is successfully stopped); GNUNET_SYSERR
1263 GNUNET_TESTING_peer_stop_async (struct GNUNET_TESTING_Peer *peer,
1264 GNUNET_TESTING_PeerStopCallback cb,
1267 if (NULL == peer->main_process)
1268 return GNUNET_SYSERR;
1269 peer->ah = GNUNET_ARM_connect (peer->cfg, &disconn_status, peer);
1270 if (NULL == peer->ah)
1271 return GNUNET_SYSERR;
1273 peer->cb_cls = cb_cls;
1279 * Destroy the peer. Releases resources locked during peer configuration.
1280 * If the peer is still running, it will be stopped AND a warning will be
1281 * printed (users of the API should stop the peer explicitly first).
1283 * @param peer peer to destroy
1286 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
1290 if (NULL != peer->main_process)
1291 GNUNET_TESTING_peer_stop (peer);
1292 if (NULL != peer->ah)
1293 GNUNET_ARM_disconnect_and_free (peer->ah);
1294 if (NULL != peer->mh)
1295 GNUNET_ARM_monitor_disconnect_and_free (peer->mh);
1296 GNUNET_free (peer->cfgfile);
1297 if (NULL != peer->cfg)
1298 GNUNET_CONFIGURATION_destroy (peer->cfg);
1299 GNUNET_free (peer->main_binary);
1300 GNUNET_free (peer->args);
1301 GNUNET_free_non_null (peer->id);
1302 if (NULL != peer->ports)
1304 for (cnt = 0; cnt < peer->nports; cnt++)
1305 GNUNET_TESTING_release_port (peer->system,
1308 GNUNET_free (peer->ports);
1315 * Start a single peer and run a test using the testing library.
1316 * Starts a peer using the given configuration and then invokes the
1317 * given callback. This function ALSO initializes the scheduler loop
1318 * and should thus be called directly from "main". The testcase
1319 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1321 * @param testdir only the directory name without any path. This is used for
1322 * all service homes; the directory will be created in a temporary
1323 * location depending on the underlying OS
1324 * @param cfgfilename name of the configuration file to use;
1325 * use NULL to only run with defaults
1326 * @param tm main function of the testcase
1327 * @param tm_cls closure for 'tm'
1328 * @return 0 on success, 1 on error
1331 GNUNET_TESTING_peer_run (const char *testdir,
1332 const char *cfgfilename,
1333 GNUNET_TESTING_TestMain tm,
1336 return GNUNET_TESTING_service_run (testdir, "arm",
1337 cfgfilename, tm, tm_cls);
1342 * Structure for holding service data
1344 struct ServiceContext
1347 * The configuration of the peer in which the service is run
1349 const struct GNUNET_CONFIGURATION_Handle *cfg;
1352 * Callback to signal service startup
1354 GNUNET_TESTING_TestMain tm;
1357 * The peer in which the service is run.
1359 struct GNUNET_TESTING_Peer *peer;
1362 * Closure for the above callback
1369 * Callback to be called when SCHEDULER has been started
1371 * @param cls the ServiceContext
1372 * @param tc the TaskContext
1375 service_run_main (void *cls,
1376 const struct GNUNET_SCHEDULER_TaskContext *tc)
1378 struct ServiceContext *sc = cls;
1380 sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1385 * Start a single service (no ARM, except of course if the given
1386 * service name is 'arm') and run a test using the testing library.
1387 * Starts a service using the given configuration and then invokes the
1388 * given callback. This function ALSO initializes the scheduler loop
1389 * and should thus be called directly from "main". The testcase
1390 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1392 * This function is useful if the testcase is for a single service
1393 * and if that service doesn't itself depend on other services.
1395 * @param testdir only the directory name without any path. This is used for
1396 * all service homes; the directory will be created in a temporary
1397 * location depending on the underlying OS
1398 * @param service_name name of the service to run
1399 * @param cfgfilename name of the configuration file to use;
1400 * use NULL to only run with defaults
1401 * @param tm main function of the testcase
1402 * @param tm_cls closure for 'tm'
1403 * @return 0 on success, 1 on error
1406 GNUNET_TESTING_service_run (const char *testdir,
1407 const char *service_name,
1408 const char *cfgfilename,
1409 GNUNET_TESTING_TestMain tm,
1412 struct ServiceContext sc;
1413 struct GNUNET_TESTING_System *system;
1414 struct GNUNET_TESTING_Peer *peer;
1415 struct GNUNET_CONFIGURATION_Handle *cfg;
1417 char *libexec_binary;
1419 GNUNET_log_setup (testdir, "WARNING", NULL);
1420 system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL);
1423 cfg = GNUNET_CONFIGURATION_create ();
1424 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1426 LOG (GNUNET_ERROR_TYPE_ERROR,
1427 _("Failed to load configuration from %s\n"), cfgfilename);
1428 GNUNET_CONFIGURATION_destroy (cfg);
1429 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1432 peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1435 GNUNET_CONFIGURATION_destroy (cfg);
1436 hostkeys_unload (system);
1437 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1440 GNUNET_free (peer->main_binary);
1441 GNUNET_free (peer->args);
1442 GNUNET_asprintf (&binary, "gnunet-service-%s", service_name);
1443 libexec_binary = GNUNET_OS_get_libexec_binary_path (binary);
1444 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, service_name, "PREFIX", &peer->main_binary))
1447 GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1448 peer->args = strdup ("");
1451 peer->args = strdup (libexec_binary);
1453 GNUNET_free (libexec_binary);
1454 GNUNET_free (binary);
1455 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1457 GNUNET_TESTING_peer_destroy (peer);
1458 GNUNET_CONFIGURATION_destroy (cfg);
1459 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1466 GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1467 if ((NULL != peer->main_process) &&
1468 (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1470 GNUNET_TESTING_peer_destroy (peer);
1471 GNUNET_CONFIGURATION_destroy (cfg);
1472 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1475 GNUNET_TESTING_peer_destroy (peer);
1476 GNUNET_CONFIGURATION_destroy (cfg);
1477 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1483 * Sometimes we use the binary name to determine which specific
1484 * test to run. In those cases, the string after the last "_"
1485 * in 'argv[0]' specifies a string that determines the configuration
1486 * file or plugin to use.
1488 * This function returns the respective substring, taking care
1489 * of issues such as binaries ending in '.exe' on W32.
1491 * @param argv0 the name of the binary
1492 * @return string between the last '_' and the '.exe' (or the end of the string),
1493 * NULL if argv0 has no '_'
1496 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1498 size_t slen = strlen (argv0) + 1;
1503 memcpy (sbuf, argv0, slen);
1504 ret = strrchr (sbuf, '_');
1507 ret++; /* skip underscore */
1508 dot = strchr (ret, '.');
1511 return GNUNET_strdup (ret);
1515 /* end of testing.c */