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 * File descriptor for the map.
102 struct GNUNET_DISK_FileHandle *map_fd;
105 * Bitmap where each TCP port that has already been reserved for
106 * some GNUnet peer is recorded. Note that we additionally need to
107 * test if a port is already in use by non-GNUnet components before
108 * assigning it to a peer/service. If we detect that a port is
109 * already in use, we also mark it in this bitmap. So all the bits
110 * that are zero merely indicate ports that MIGHT be available for
113 uint32_t reserved_tcp_ports[65536 / 32];
116 * Bitmap where each UDP port that has already been reserved for
117 * some GNUnet peer is recorded. Note that we additionally need to
118 * test if a port is already in use by non-GNUnet components before
119 * assigning it to a peer/service. If we detect that a port is
120 * already in use, we also mark it in this bitmap. So all the bits
121 * that are zero merely indicate ports that MIGHT be available for
124 uint32_t reserved_udp_ports[65536 / 32];
127 * Counter we use to make service home paths unique on this system;
128 * the full path consists of the tmppath and this number. Each
129 * UNIXPATH for a peer is also modified to include the respective
130 * path counter to ensure uniqueness. This field is incremented
131 * by one for each configured peer. Even if peers are destroyed,
132 * we never re-use path counters.
134 uint32_t path_counter;
137 * The number of hostkeys
139 uint32_t total_hostkeys;
142 * Lowest port we are allowed to use.
147 * Highest port we are allowed to use.
154 * Handle for a GNUnet peer controlled by testing.
156 struct GNUNET_TESTING_Peer
159 * The TESTING system associated with this peer
161 struct GNUNET_TESTING_System *system;
164 * Path to the configuration file for this peer.
169 * Binary to be executed during 'GNUNET_TESTING_peer_start'.
170 * Typically 'gnunet-service-arm' (but can be set to a
171 * specific service by 'GNUNET_TESTING_service_run' if
178 * Handle to the running binary of the service, NULL if the
179 * peer/service is currently not running.
181 struct GNUNET_OS_Process *main_process;
184 * The handle to the peer's ARM service
186 struct GNUNET_ARM_Handle *ah;
189 * Handle to ARM monitoring
191 struct GNUNET_ARM_MonitorHandle *mh;
194 * The config of the peer
196 struct GNUNET_CONFIGURATION_Handle *cfg;
199 * The callback to call asynchronously when a peer is stopped
201 GNUNET_TESTING_PeerStopCallback cb;
204 * The closure for the above callback
209 * The cached identity of this peer. Will be populated on call to
210 * GNUNET_TESTING_peer_get_identity()
212 struct GNUNET_PeerIdentity *id;
215 * Array of ports currently allocated to this peer. These ports will be
216 * released upon peer destroy and can be used by other peers which are
222 * The number of ports in the above array
227 * The keynumber of this peer's hostkey
234 * Testing includes a number of pre-created hostkeys for faster peer
235 * startup. This function loads such keys into memory from a file.
237 * @param system the testing system handle
238 * @return GNUNET_OK on success; GNUNET_SYSERR on error
241 hostkeys_load (struct GNUNET_TESTING_System *system)
247 GNUNET_assert (NULL == system->hostkeys_data);
248 data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
249 GNUNET_asprintf (&filename, "%s/testing_hostkeys.ecc", data_dir);
250 GNUNET_free (data_dir);
252 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
254 LOG (GNUNET_ERROR_TYPE_ERROR,
255 _("Hostkeys file not found: %s\n"), filename);
256 GNUNET_free (filename);
257 return GNUNET_SYSERR;
259 /* Check hostkey file size, read entire thing into memory */
261 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
265 GNUNET_free (filename);
266 return GNUNET_SYSERR; /* File is empty */
268 if (0 != (fs % GNUNET_TESTING_HOSTKEYFILESIZE))
270 LOG (GNUNET_ERROR_TYPE_ERROR,
271 _("Incorrect hostkey file format: %s\n"), filename);
272 GNUNET_free (filename);
273 return GNUNET_SYSERR;
275 system->map_fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
276 GNUNET_DISK_PERM_NONE);
277 if (NULL == system->map_fd)
279 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename);
280 GNUNET_free (filename);
281 return GNUNET_SYSERR;
283 system->total_hostkeys = fs / GNUNET_TESTING_HOSTKEYFILESIZE;
284 system->hostkeys_data = GNUNET_DISK_file_map (system->map_fd,
286 GNUNET_DISK_MAP_TYPE_READ,
288 GNUNET_free (filename);
294 * Function to remove the loaded hostkeys
296 * @param system the testing system handle
299 hostkeys_unload (struct GNUNET_TESTING_System *system)
301 GNUNET_break (NULL != system->hostkeys_data);
302 system->hostkeys_data = NULL;
303 GNUNET_DISK_file_unmap (system->map);
305 GNUNET_DISK_file_close (system->map_fd);
306 system->map_fd = NULL;
307 system->hostkeys_data = NULL;
308 system->total_hostkeys = 0;
313 * Create a system handle. There must only be one system
314 * handle per operating system.
316 * @param testdir only the directory name without any path. This is used for
317 * all service homes; the directory will be created in a temporary
318 * location depending on the underlying OS
319 * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
320 * service configurations generated to allow control connections from
321 * this ip. This can either be a single ip address or a network address
323 * @param hostname the hostname of the system we are using for testing; NULL for
325 * @param lowport lowest port number this system is allowed to allocate (inclusive)
326 * @param highport highest port number this system is allowed to allocate (exclusive)
327 * @return handle to this system, NULL on error
329 struct GNUNET_TESTING_System *
330 GNUNET_TESTING_system_create_with_portrange (const char *testdir,
331 const char *trusted_ip,
332 const char *hostname,
336 struct GNUNET_TESTING_System *system;
338 GNUNET_assert (NULL != testdir);
339 system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
340 system->tmppath = GNUNET_DISK_mkdtemp (testdir);
341 system->lowport = lowport;
342 system->highport = highport;
343 if (NULL == system->tmppath)
345 GNUNET_free (system);
348 if (NULL != trusted_ip)
349 system->trusted_ip = GNUNET_strdup (trusted_ip);
350 if (NULL != hostname)
351 system->hostname = GNUNET_strdup (hostname);
352 if (GNUNET_OK != hostkeys_load (system))
354 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
362 * Create a system handle. There must only be one system handle per operating
363 * system. Uses a default range for allowed ports. Ports are still tested for
366 * @param testdir only the directory name without any path. This is used for all
367 * service homes; the directory will be created in a temporary location
368 * depending on the underlying OS
369 * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
370 * service configurations generated to allow control connections from
371 * this ip. This can either be a single ip address or a network address
373 * @param hostname the hostname of the system we are using for testing; NULL for
375 * @return handle to this system, NULL on error
377 struct GNUNET_TESTING_System *
378 GNUNET_TESTING_system_create (const char *testdir,
379 const char *trusted_ip,
380 const char *hostname)
382 return GNUNET_TESTING_system_create_with_portrange (testdir,
391 * Free system resources.
393 * @param system system to be freed
394 * @param remove_paths should the 'testdir' and all subdirectories
395 * be removed (clean up on shutdown)?
398 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
401 if (NULL != system->hostkeys_data)
402 hostkeys_unload (system);
403 if (GNUNET_YES == remove_paths)
404 GNUNET_DISK_directory_remove (system->tmppath);
405 GNUNET_free (system->tmppath);
406 GNUNET_free_non_null (system->trusted_ip);
407 GNUNET_free_non_null (system->hostname);
408 GNUNET_free (system);
413 * Reserve a TCP or UDP port for a peer.
415 * @param system system to use for reservation tracking
416 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
417 * @return 0 if no free port was available
420 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system,
423 struct GNUNET_NETWORK_Handle *socket;
424 struct addrinfo hint;
425 struct addrinfo *ret;
427 uint32_t *port_buckets;
436 FIXME: Instead of using getaddrinfo we should try to determine the port
437 status by the following heurestics.
439 On systems which support both IPv4 and IPv6, only ports open on both
440 address families are considered open.
441 On system with either IPv4 or IPv6. A port is considered open if it's
442 open in the respective address family
444 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
445 hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM;
446 hint.ai_protocol = 0;
449 hint.ai_canonname = NULL;
451 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
452 port_buckets = (GNUNET_YES == is_tcp) ?
453 system->reserved_tcp_ports : system->reserved_udp_ports;
454 for (index = (system->lowport / 32) + 1; index < (system->highport / 32); index++)
456 xor_image = (UINT32_MAX ^ port_buckets[index]);
457 if (0 == xor_image) /* Ports in the bucket are full */
459 pos = system->lowport % 32;
462 if (0 == ((xor_image >> pos) & 1U))
467 open_port = (index * 32) + pos;
468 if (open_port >= system->highport)
470 GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
472 GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
473 GNUNET_free (open_port_str);
474 bind_status = GNUNET_NO;
475 for (ai = ret; NULL != ai; ai = ai->ai_next)
477 socket = GNUNET_NETWORK_socket_create (ai->ai_family,
478 (GNUNET_YES == is_tcp) ?
479 SOCK_STREAM : SOCK_DGRAM,
483 bind_status = GNUNET_NETWORK_socket_bind (socket,
486 GNUNET_NETWORK_socket_close (socket);
487 if (GNUNET_OK != bind_status)
490 port_buckets[index] |= (1U << pos); /* Set the port bit */
492 if (GNUNET_OK == bind_status)
494 LOG (GNUNET_ERROR_TYPE_DEBUG,
495 "Found a free port %u\n", (unsigned int) open_port);
506 * Release reservation of a TCP or UDP port for a peer
507 * (used during GNUNET_TESTING_peer_destroy).
509 * @param system system to use for reservation tracking
510 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
511 * @param port reserved port to release
514 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
518 uint32_t *port_buckets;
522 port_buckets = (GNUNET_YES == is_tcp) ?
523 system->reserved_tcp_ports : system->reserved_udp_ports;
526 LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
527 if (0 == (port_buckets[bucket] & (1U << pos)))
529 GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
532 port_buckets[bucket] &= ~(1U << pos);
537 * Testing includes a number of pre-created hostkeys for
538 * faster peer startup. This function can be used to
539 * access the n-th key of those pre-created hostkeys; note
540 * that these keys are ONLY useful for testing and not
541 * secure as the private keys are part of the public
542 * GNUnet source code.
544 * This is primarily a helper function used internally
545 * by 'GNUNET_TESTING_peer_configure'.
547 * @param system the testing system handle
548 * @param key_number desired pre-created hostkey to obtain
549 * @param id set to the peer's identity (hash of the public
550 * key; if NULL, GNUNET_SYSERR is returned immediately
551 * @return NULL on error (not enough keys)
553 struct GNUNET_CRYPTO_EccPrivateKey *
554 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
556 struct GNUNET_PeerIdentity *id)
558 struct GNUNET_CRYPTO_EccPrivateKey *private_key;
559 struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded public_key;
561 if ((NULL == id) || (NULL == system->hostkeys_data))
563 if (key_number >= system->total_hostkeys)
565 LOG (GNUNET_ERROR_TYPE_ERROR,
566 _("Key number %u does not exist\n"), key_number);
569 private_key = GNUNET_CRYPTO_ecc_decode_key (system->hostkeys_data +
571 GNUNET_TESTING_HOSTKEYFILESIZE),
572 GNUNET_TESTING_HOSTKEYFILESIZE,
574 if (NULL == private_key)
576 LOG (GNUNET_ERROR_TYPE_ERROR,
577 _("Error while decoding key %u\n"), key_number);
580 GNUNET_CRYPTO_ecc_key_get_public (private_key, &public_key);
581 GNUNET_CRYPTO_hash (&public_key,
582 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
589 * Structure for holding data to build new configurations from a configuration
595 * The system for which we are building configurations
597 struct GNUNET_TESTING_System *system;
600 * The configuration we are building
602 struct GNUNET_CONFIGURATION_Handle *cfg;
605 * The customized service home path for this peer
610 * Array of ports currently allocated to this peer. These ports will be
611 * released upon peer destroy and can be used by other peers which are
617 * The number of ports in the above array
622 * build status - to signal error while building a configuration
629 * Function to iterate over options. Copies
630 * the options to the target configuration,
631 * updating PORT values as needed.
633 * @param cls the UpdateContext
634 * @param section name of the section
635 * @param option name of the option
636 * @param value value of the option
639 update_config (void *cls, const char *section, const char *option,
642 struct UpdateContext *uc = cls;
646 char *single_variable;
647 char *per_host_variable;
648 unsigned long long num_per_host;
651 if (GNUNET_OK != uc->status)
653 if (! ((0 == strcmp (option, "PORT"))
654 || (0 == strcmp (option, "UNIXPATH"))
655 || (0 == strcmp (option, "HOSTNAME"))))
657 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
658 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
659 if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
663 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
666 /* FIXME: What about UDP? */
667 new_port = GNUNET_TESTING_reserve_port (uc->system, GNUNET_YES);
670 uc->status = GNUNET_SYSERR;
671 GNUNET_free (single_variable);
672 GNUNET_free (per_host_variable);
675 GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
677 GNUNET_array_append (uc->ports, uc->nports, new_port);
679 else if ((ival != 0) &&
681 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
683 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
687 /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
688 /* ival + ctx->fdnum % num_per_host); */
690 GNUNET_break (0); /* FIXME */
693 if (0 == strcmp (option, "UNIXPATH"))
696 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
699 GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock",
700 uc->service_home, section);
703 else if ((GNUNET_YES ==
704 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
709 GNUNET_break(0); /* FIXME */
712 if (0 == strcmp (option, "HOSTNAME"))
714 value = (NULL == uc->system->hostname) ? "localhost" : uc->system->hostname;
716 GNUNET_free (single_variable);
717 GNUNET_free (per_host_variable);
718 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
723 * Section iterator to set ACCEPT_FROM/ACCEPT_FROM6 to include the address of
724 * 'trusted_hosts' in all sections
726 * @param cls the UpdateContext
727 * @param section name of the section
730 update_config_sections (void *cls,
733 struct UpdateContext *uc = cls;
737 char *orig_allowed_hosts;
739 char *ACCEPT_FROM_key;
745 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
746 "TESTING_IGNORE_KEYS"))
750 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section,
751 "TESTING_IGNORE_KEYS", &val));
753 for (ikeys_cnt = 0; NULL != (ptr = strstr (ptr, ";")); ikeys_cnt++)
759 ikeys = GNUNET_malloc ((sizeof (char *)) * ikeys_cnt);
761 for (key = 0; key < ikeys_cnt; key++)
764 ptr = strstr (ptr, ";");
772 for (key = 0; key < ikeys_cnt; key++)
774 if (NULL != strstr (ikeys[key], "ADVERTISED_PORT"))
777 if ((key == ikeys_cnt) &&
778 (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
782 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "PORT", &ptr))
784 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section,
785 "ADVERTISED_PORT", ptr);
789 for (key = 0; key < ikeys_cnt; key++)
791 if (NULL != strstr (ikeys[key], "ACCEPT_FROM"))
800 GNUNET_free_non_null (val);
801 ACCEPT_FROM_key = "ACCEPT_FROM";
802 if ((NULL != uc->system->trusted_ip) &&
803 (NULL != strstr (uc->system->trusted_ip, ":"))) /* IPv6 in use */
804 ACCEPT_FROM_key = "ACCEPT_FROM6";
806 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, ACCEPT_FROM_key,
807 &orig_allowed_hosts))
809 orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
811 if (NULL == uc->system->trusted_ip)
812 allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
814 GNUNET_asprintf (&allowed_hosts, "%s%s;", orig_allowed_hosts,
815 uc->system->trusted_ip);
816 GNUNET_free (orig_allowed_hosts);
817 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, ACCEPT_FROM_key,
819 GNUNET_free (allowed_hosts);
824 * Create a new configuration using the given configuration as a template;
825 * ports and paths will be modified to select available ports on the local
826 * system. The default configuration will be available in PATHS section under
827 * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS
828 * section to the temporary directory specific to this configuration. If we run
829 * out of "*port" numbers, return SYSERR.
831 * This is primarily a helper function used internally
832 * by 'GNUNET_TESTING_peer_configure'.
834 * @param system system to use to coordinate resource usage
835 * @param cfg template configuration to update
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 arm handle to the ARM connection
1226 * @param connected GNUNET_YES if connected, GNUNET_NO if disconnected,
1227 * GNUNET_SYSERR on error.
1230 disconn_status (void *cls, struct GNUNET_ARM_Handle *arm,
1233 struct GNUNET_TESTING_Peer *peer = cls;
1235 if (GNUNET_SYSERR == connected)
1237 peer->cb (peer->cb_cls, peer, connected);
1240 if (GNUNET_YES == connected)
1242 GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_kill (peer));
1245 GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_wait (peer));
1246 GNUNET_ARM_disconnect_and_free (peer->ah);
1248 peer->cb (peer->cb_cls, peer, GNUNET_YES);
1253 * Stop a peer asynchronously using ARM API. Peer's shutdown is signaled
1254 * through the GNUNET_TESTING_PeerStopCallback().
1256 * @param peer the peer to stop
1257 * @param cb the callback to signal peer shutdown
1258 * @param cb_cls closure for the above callback
1259 * @return GNUNET_OK upon successfully giving the request to the ARM API (this
1260 * does not mean that the peer is successfully stopped); GNUNET_SYSERR
1264 GNUNET_TESTING_peer_stop_async (struct GNUNET_TESTING_Peer *peer,
1265 GNUNET_TESTING_PeerStopCallback cb,
1268 if (NULL == peer->main_process)
1269 return GNUNET_SYSERR;
1270 peer->ah = GNUNET_ARM_connect (peer->cfg, &disconn_status, peer);
1271 if (NULL == peer->ah)
1272 return GNUNET_SYSERR;
1274 peer->cb_cls = cb_cls;
1280 * Destroy the peer. Releases resources locked during peer configuration.
1281 * If the peer is still running, it will be stopped AND a warning will be
1282 * printed (users of the API should stop the peer explicitly first).
1284 * @param peer peer to destroy
1287 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
1291 if (NULL != peer->main_process)
1292 GNUNET_TESTING_peer_stop (peer);
1293 if (NULL != peer->ah)
1294 GNUNET_ARM_disconnect_and_free (peer->ah);
1295 if (NULL != peer->mh)
1296 GNUNET_ARM_monitor_disconnect_and_free (peer->mh);
1297 GNUNET_free (peer->cfgfile);
1298 if (NULL != peer->cfg)
1299 GNUNET_CONFIGURATION_destroy (peer->cfg);
1300 GNUNET_free (peer->main_binary);
1301 GNUNET_free (peer->args);
1302 GNUNET_free_non_null (peer->id);
1303 if (NULL != peer->ports)
1305 for (cnt = 0; cnt < peer->nports; cnt++)
1306 GNUNET_TESTING_release_port (peer->system,
1309 GNUNET_free (peer->ports);
1316 * Start a single peer and run a test using the testing library.
1317 * Starts a peer using the given configuration and then invokes the
1318 * given callback. This function ALSO initializes the scheduler loop
1319 * and should thus be called directly from "main". The testcase
1320 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1322 * @param testdir only the directory name without any path. This is used for
1323 * all service homes; the directory will be created in a temporary
1324 * location depending on the underlying OS
1325 * @param cfgfilename name of the configuration file to use;
1326 * use NULL to only run with defaults
1327 * @param tm main function of the testcase
1328 * @param tm_cls closure for 'tm'
1329 * @return 0 on success, 1 on error
1332 GNUNET_TESTING_peer_run (const char *testdir,
1333 const char *cfgfilename,
1334 GNUNET_TESTING_TestMain tm,
1337 return GNUNET_TESTING_service_run (testdir, "arm",
1338 cfgfilename, tm, tm_cls);
1343 * Structure for holding service data
1345 struct ServiceContext
1348 * The configuration of the peer in which the service is run
1350 const struct GNUNET_CONFIGURATION_Handle *cfg;
1353 * Callback to signal service startup
1355 GNUNET_TESTING_TestMain tm;
1358 * The peer in which the service is run.
1360 struct GNUNET_TESTING_Peer *peer;
1363 * Closure for the above callback
1370 * Callback to be called when SCHEDULER has been started
1372 * @param cls the ServiceContext
1373 * @param tc the TaskContext
1376 service_run_main (void *cls,
1377 const struct GNUNET_SCHEDULER_TaskContext *tc)
1379 struct ServiceContext *sc = cls;
1381 sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1386 * Start a single service (no ARM, except of course if the given
1387 * service name is 'arm') and run a test using the testing library.
1388 * Starts a service using the given configuration and then invokes the
1389 * given callback. This function ALSO initializes the scheduler loop
1390 * and should thus be called directly from "main". The testcase
1391 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1393 * This function is useful if the testcase is for a single service
1394 * and if that service doesn't itself depend on other services.
1396 * @param testdir only the directory name without any path. This is used for
1397 * all service homes; the directory will be created in a temporary
1398 * location depending on the underlying OS
1399 * @param service_name name of the service to run
1400 * @param cfgfilename name of the configuration file to use;
1401 * use NULL to only run with defaults
1402 * @param tm main function of the testcase
1403 * @param tm_cls closure for 'tm'
1404 * @return 0 on success, 1 on error
1407 GNUNET_TESTING_service_run (const char *testdir,
1408 const char *service_name,
1409 const char *cfgfilename,
1410 GNUNET_TESTING_TestMain tm,
1413 struct ServiceContext sc;
1414 struct GNUNET_TESTING_System *system;
1415 struct GNUNET_TESTING_Peer *peer;
1416 struct GNUNET_CONFIGURATION_Handle *cfg;
1418 char *libexec_binary;
1420 GNUNET_log_setup (testdir, "WARNING", NULL);
1421 system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL);
1424 cfg = GNUNET_CONFIGURATION_create ();
1425 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1427 LOG (GNUNET_ERROR_TYPE_ERROR,
1428 _("Failed to load configuration from %s\n"), cfgfilename);
1429 GNUNET_CONFIGURATION_destroy (cfg);
1430 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1433 peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1436 GNUNET_CONFIGURATION_destroy (cfg);
1437 hostkeys_unload (system);
1438 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1441 GNUNET_free (peer->main_binary);
1442 GNUNET_free (peer->args);
1443 GNUNET_asprintf (&binary, "gnunet-service-%s", service_name);
1444 libexec_binary = GNUNET_OS_get_libexec_binary_path (binary);
1445 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, service_name, "PREFIX", &peer->main_binary))
1448 GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1449 peer->args = strdup ("");
1452 peer->args = strdup (libexec_binary);
1454 GNUNET_free (libexec_binary);
1455 GNUNET_free (binary);
1456 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1458 GNUNET_TESTING_peer_destroy (peer);
1459 GNUNET_CONFIGURATION_destroy (cfg);
1460 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1467 GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1468 if ((NULL != peer->main_process) &&
1469 (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1471 GNUNET_TESTING_peer_destroy (peer);
1472 GNUNET_CONFIGURATION_destroy (cfg);
1473 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1476 GNUNET_TESTING_peer_destroy (peer);
1477 GNUNET_CONFIGURATION_destroy (cfg);
1478 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1484 * Sometimes we use the binary name to determine which specific
1485 * test to run. In those cases, the string after the last "_"
1486 * in 'argv[0]' specifies a string that determines the configuration
1487 * file or plugin to use.
1489 * This function returns the respective substring, taking care
1490 * of issues such as binaries ending in '.exe' on W32.
1492 * @param argv0 the name of the binary
1493 * @return string between the last '_' and the '.exe' (or the end of the string),
1494 * NULL if argv0 has no '_'
1497 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1499 size_t slen = strlen (argv0) + 1;
1504 memcpy (sbuf, argv0, slen);
1505 ret = strrchr (sbuf, '_');
1508 ret++; /* skip underscore */
1509 dot = strchr (ret, '.');
1512 return GNUNET_strdup (ret);
1516 /* end of testing.c */