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 * @param ports array with port numbers used in the created configuration.
819 * Will be updated upon successful return. Can be NULL
820 * @param nports the size of the `ports' array. Will be updated.
821 * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
822 * be incomplete and should not be used there upon
825 GNUNET_TESTING_configuration_create_ (struct GNUNET_TESTING_System *system,
826 struct GNUNET_CONFIGURATION_Handle *cfg,
828 unsigned int *nports)
830 struct UpdateContext uc;
831 char *default_config;
835 uc.status = GNUNET_OK;
838 GNUNET_asprintf (&uc.service_home, "%s/%u", system->tmppath,
839 system->path_counter++);
840 GNUNET_asprintf (&default_config, "%s/config", uc.service_home);
841 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
843 GNUNET_CONFIGURATION_set_value_string (cfg, "arm", "CONFIG",
845 GNUNET_free (default_config);
846 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME",
848 /* make PORTs and UNIXPATHs unique */
849 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
850 /* allow connections to services from system trusted_ip host */
851 GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
852 /* enable loopback-based connections between peers */
853 GNUNET_CONFIGURATION_set_value_string (cfg,
855 "USE_LOCALADDR", "YES");
856 GNUNET_free (uc.service_home);
857 if ((NULL != ports) && (NULL != nports))
863 GNUNET_free_non_null (uc.ports);
869 * Create a new configuration using the given configuration as a template;
870 * ports and paths will be modified to select available ports on the local
871 * system. The default configuration will be available in PATHS section under
872 * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS
873 * section to the temporary directory specific to this configuration. If we run
874 * out of "*port" numbers, return SYSERR.
876 * This is primarily a helper function used internally
877 * by 'GNUNET_TESTING_peer_configure'.
879 * @param system system to use to coordinate resource usage
880 * @param cfg template configuration to update
881 * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
882 * be incomplete and should not be used there upon
885 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
886 struct GNUNET_CONFIGURATION_Handle *cfg)
888 return GNUNET_TESTING_configuration_create_ (system, cfg, NULL, NULL);
893 * Configure a GNUnet peer. GNUnet must be installed on the local
894 * system and available in the PATH.
896 * @param system system to use to coordinate resource usage
897 * @param cfg configuration to use; will be UPDATED (to reflect needed
898 * changes in port numbers and paths)
899 * @param key_number number of the hostkey to use for the peer
900 * @param id identifier for the daemon, will be set, can be NULL
901 * @param emsg set to freshly allocated error message (set to NULL on success),
903 * @return handle to the peer, NULL on error
905 struct GNUNET_TESTING_Peer *
906 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
907 struct GNUNET_CONFIGURATION_Handle *cfg,
909 struct GNUNET_PeerIdentity *id,
912 struct GNUNET_TESTING_Peer *peer;
913 struct GNUNET_DISK_FileHandle *fd;
915 char hostkey_filename[128];
916 char *config_filename;
917 char *libexec_binary;
919 struct GNUNET_CRYPTO_EccPrivateKey *pk;
927 if (GNUNET_OK != GNUNET_TESTING_configuration_create_ (system, cfg,
930 GNUNET_asprintf (&emsg_,
931 _("Failed to create configuration for peer "
932 "(not enough free ports?)\n"));
935 if (key_number >= system->total_hostkeys)
937 GNUNET_asprintf (&emsg_,
938 _("You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"),
939 (unsigned int) system->total_hostkeys);
944 (NULL == (pk = GNUNET_TESTING_hostkey_get (system, key_number, id))))
946 GNUNET_asprintf (&emsg_,
947 _("Failed to initialize hostkey for peer %u\n"),
948 (unsigned int) key_number);
952 GNUNET_CRYPTO_ecc_key_free (pk);
953 GNUNET_assert (GNUNET_OK ==
954 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
957 /* FIXME: might be better to evaluate actual configuration option here... */
958 GNUNET_snprintf (hostkey_filename, sizeof (hostkey_filename), "%s/private.ecc",
960 GNUNET_free (service_home);
961 fd = GNUNET_DISK_file_open (hostkey_filename,
962 GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
963 GNUNET_DISK_PERM_USER_READ
964 | GNUNET_DISK_PERM_USER_WRITE);
967 GNUNET_asprintf (&emsg_, _("Cannot open hostkey file: %s\n"),
971 if (GNUNET_TESTING_HOSTKEYFILESIZE !=
972 GNUNET_DISK_file_write (fd, system->hostkeys_data
973 + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE),
974 GNUNET_TESTING_HOSTKEYFILESIZE))
976 GNUNET_asprintf (&emsg_,
977 _("Failed to write hostkey file for peer %u: %s\n"),
978 (unsigned int) key_number,
980 GNUNET_DISK_file_close (fd);
983 GNUNET_DISK_file_close (fd);
984 GNUNET_assert (GNUNET_OK ==
985 GNUNET_CONFIGURATION_get_value_string
986 (cfg, "PATHS", "DEFAULTCONFIG", &config_filename));
987 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
989 GNUNET_asprintf (&emsg_,
990 _("Failed to write configuration file `%s' for peer %u: %s\n"),
992 (unsigned int) key_number,
994 GNUNET_free (config_filename);
997 peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
998 peer->cfgfile = config_filename; /* Free in peer_destroy */
999 peer->cfg = GNUNET_CONFIGURATION_dup (cfg);
1000 libexec_binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
1001 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "arm", "PREFIX", &peer->main_binary))
1004 GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1005 peer->args = strdup ("");
1008 peer->args = strdup (libexec_binary);
1009 peer->system = system;
1010 peer->key_number = key_number;
1011 GNUNET_free (libexec_binary);
1012 peer->ports = ports; /* Free in peer_destroy */
1013 peer->nports = nports;
1017 GNUNET_free_non_null (ports);
1018 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
1022 GNUNET_free (emsg_);
1028 * Obtain the peer identity from a peer handle.
1030 * @param peer peer handle for which we want the peer's identity
1031 * @param id identifier for the daemon, will be set
1034 GNUNET_TESTING_peer_get_identity (struct GNUNET_TESTING_Peer *peer,
1035 struct GNUNET_PeerIdentity *id)
1037 if (NULL != peer->id)
1039 memcpy (id, peer->id, sizeof (struct GNUNET_PeerIdentity));
1042 peer->id = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
1043 GNUNET_CRYPTO_ecc_key_free (GNUNET_TESTING_hostkey_get (peer->system,
1046 memcpy (id, peer->id, sizeof (struct GNUNET_PeerIdentity));
1053 * @param peer peer to start
1054 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
1057 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
1059 if (NULL != peer->main_process)
1062 return GNUNET_SYSERR;
1064 GNUNET_assert (NULL != peer->cfgfile);
1065 peer->main_process = GNUNET_OS_start_process (PIPE_CONTROL,
1066 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
1074 if (NULL == peer->main_process)
1076 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1077 _("Failed to start `%s': %s\n"),
1080 return GNUNET_SYSERR;
1087 * Start a service at a peer using its ARM service
1089 * @param peer the peer whose service has to be started
1090 * @param service_name name of the service to start
1091 * @param timeout how long should the ARM API try to send the request to start
1093 * @param cont the callback to call with result and status from ARM API
1094 * @param cont_cls the closure for the above callback
1095 * @return GNUNET_OK upon successfully queuing the service start request;
1096 * GNUNET_SYSERR upon error
1099 GNUNET_TESTING_peer_service_start (struct GNUNET_TESTING_Peer *peer,
1100 const char *service_name,
1101 struct GNUNET_TIME_Relative timeout,
1102 GNUNET_ARM_ResultCallback cont,
1105 if (NULL == peer->ah)
1106 return GNUNET_SYSERR;
1107 GNUNET_ARM_request_service_start (peer->ah,
1109 GNUNET_OS_INHERIT_STD_ALL,
1117 * Stop a service at a peer using its ARM service
1119 * @param peer the peer whose service has to be stopped
1120 * @param service_name name of the service to stop
1121 * @param timeout how long should the ARM API try to send the request to stop
1123 * @param cont the callback to call with result and status from ARM API
1124 * @param cont_cls the closure for the above callback
1125 * @return GNUNET_OK upon successfully queuing the service stop request;
1126 * GNUNET_SYSERR upon error
1129 GNUNET_TESTING_peer_service_stop (struct GNUNET_TESTING_Peer *peer,
1130 const char *service_name,
1131 struct GNUNET_TIME_Relative timeout,
1132 GNUNET_ARM_ResultCallback cont,
1135 if (NULL == peer->ah)
1136 return GNUNET_SYSERR;
1137 GNUNET_ARM_request_service_stop (peer->ah,
1146 * Sends SIGTERM to the peer's main process
1148 * @param peer the handle to the peer
1149 * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1150 * or upon any error while sending SIGTERM
1153 GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer)
1155 if (NULL == peer->main_process)
1158 return GNUNET_SYSERR;
1160 return (0 == GNUNET_OS_process_kill (peer->main_process, SIGTERM)) ?
1161 GNUNET_OK : GNUNET_SYSERR;
1166 * Waits for a peer to terminate. The peer's main process will also be destroyed.
1168 * @param peer the handle to the peer
1169 * @return GNUNET_OK if successful; GNUNET_SYSERR if the main process is NULL
1170 * or upon any error while waiting
1173 GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer)
1177 if (NULL == peer->main_process)
1180 return GNUNET_SYSERR;
1182 ret = GNUNET_OS_process_wait (peer->main_process);
1183 GNUNET_OS_process_destroy (peer->main_process);
1184 peer->main_process = NULL;
1192 * @param peer peer to stop
1193 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1196 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
1198 if (GNUNET_SYSERR == GNUNET_TESTING_peer_kill (peer))
1199 return GNUNET_SYSERR;
1200 if (GNUNET_SYSERR == GNUNET_TESTING_peer_wait (peer))
1201 return GNUNET_SYSERR;
1207 * Function called whenever we connect to or disconnect from ARM.
1209 * @param cls closure
1210 * @param arm handle to the ARM connection
1211 * @param connected GNUNET_YES if connected, GNUNET_NO if disconnected,
1212 * GNUNET_SYSERR on error.
1215 disconn_status (void *cls, struct GNUNET_ARM_Handle *arm,
1218 struct GNUNET_TESTING_Peer *peer = cls;
1220 if (GNUNET_SYSERR == connected)
1222 peer->cb (peer->cb_cls, peer, connected);
1225 if (GNUNET_YES == connected)
1227 GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_kill (peer));
1230 GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_wait (peer));
1231 GNUNET_ARM_disconnect_and_free (peer->ah);
1233 peer->cb (peer->cb_cls, peer, GNUNET_YES);
1238 * Stop a peer asynchronously using ARM API. Peer's shutdown is signaled
1239 * through the GNUNET_TESTING_PeerStopCallback().
1241 * @param peer the peer to stop
1242 * @param cb the callback to signal peer shutdown
1243 * @param cb_cls closure for the above callback
1244 * @return GNUNET_OK upon successfully giving the request to the ARM API (this
1245 * does not mean that the peer is successfully stopped); GNUNET_SYSERR
1249 GNUNET_TESTING_peer_stop_async (struct GNUNET_TESTING_Peer *peer,
1250 GNUNET_TESTING_PeerStopCallback cb,
1253 if (NULL == peer->main_process)
1254 return GNUNET_SYSERR;
1255 peer->ah = GNUNET_ARM_connect (peer->cfg, &disconn_status, peer);
1256 if (NULL == peer->ah)
1257 return GNUNET_SYSERR;
1259 peer->cb_cls = cb_cls;
1265 * Destroy the peer. Releases resources locked during peer configuration.
1266 * If the peer is still running, it will be stopped AND a warning will be
1267 * printed (users of the API should stop the peer explicitly first).
1269 * @param peer peer to destroy
1272 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
1276 if (NULL != peer->main_process)
1277 GNUNET_TESTING_peer_stop (peer);
1278 if (NULL != peer->ah)
1279 GNUNET_ARM_disconnect_and_free (peer->ah);
1280 if (NULL != peer->mh)
1281 GNUNET_ARM_monitor_disconnect_and_free (peer->mh);
1282 GNUNET_free (peer->cfgfile);
1283 if (NULL != peer->cfg)
1284 GNUNET_CONFIGURATION_destroy (peer->cfg);
1285 GNUNET_free (peer->main_binary);
1286 GNUNET_free (peer->args);
1287 GNUNET_free_non_null (peer->id);
1288 if (NULL != peer->ports)
1290 for (cnt = 0; cnt < peer->nports; cnt++)
1291 GNUNET_TESTING_release_port (peer->system,
1294 GNUNET_free (peer->ports);
1301 * Start a single peer and run a test using the testing library.
1302 * Starts a peer using the given configuration and then invokes the
1303 * given callback. This function ALSO initializes the scheduler loop
1304 * and should thus be called directly from "main". The testcase
1305 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1307 * @param testdir only the directory name without any path. This is used for
1308 * all service homes; the directory will be created in a temporary
1309 * location depending on the underlying OS
1310 * @param cfgfilename name of the configuration file to use;
1311 * use NULL to only run with defaults
1312 * @param tm main function of the testcase
1313 * @param tm_cls closure for 'tm'
1314 * @return 0 on success, 1 on error
1317 GNUNET_TESTING_peer_run (const char *testdir,
1318 const char *cfgfilename,
1319 GNUNET_TESTING_TestMain tm,
1322 return GNUNET_TESTING_service_run (testdir, "arm",
1323 cfgfilename, tm, tm_cls);
1328 * Structure for holding service data
1330 struct ServiceContext
1333 * The configuration of the peer in which the service is run
1335 const struct GNUNET_CONFIGURATION_Handle *cfg;
1338 * Callback to signal service startup
1340 GNUNET_TESTING_TestMain tm;
1343 * The peer in which the service is run.
1345 struct GNUNET_TESTING_Peer *peer;
1348 * Closure for the above callback
1355 * Callback to be called when SCHEDULER has been started
1357 * @param cls the ServiceContext
1358 * @param tc the TaskContext
1361 service_run_main (void *cls,
1362 const struct GNUNET_SCHEDULER_TaskContext *tc)
1364 struct ServiceContext *sc = cls;
1366 sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1371 * Start a single service (no ARM, except of course if the given
1372 * service name is 'arm') and run a test using the testing library.
1373 * Starts a service using the given configuration and then invokes the
1374 * given callback. This function ALSO initializes the scheduler loop
1375 * and should thus be called directly from "main". The testcase
1376 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1378 * This function is useful if the testcase is for a single service
1379 * and if that service doesn't itself depend on other services.
1381 * @param testdir only the directory name without any path. This is used for
1382 * all service homes; the directory will be created in a temporary
1383 * location depending on the underlying OS
1384 * @param service_name name of the service to run
1385 * @param cfgfilename name of the configuration file to use;
1386 * use NULL to only run with defaults
1387 * @param tm main function of the testcase
1388 * @param tm_cls closure for 'tm'
1389 * @return 0 on success, 1 on error
1392 GNUNET_TESTING_service_run (const char *testdir,
1393 const char *service_name,
1394 const char *cfgfilename,
1395 GNUNET_TESTING_TestMain tm,
1398 struct ServiceContext sc;
1399 struct GNUNET_TESTING_System *system;
1400 struct GNUNET_TESTING_Peer *peer;
1401 struct GNUNET_CONFIGURATION_Handle *cfg;
1403 char *libexec_binary;
1405 GNUNET_log_setup (testdir, "WARNING", NULL);
1406 system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL);
1409 cfg = GNUNET_CONFIGURATION_create ();
1410 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1412 LOG (GNUNET_ERROR_TYPE_ERROR,
1413 _("Failed to load configuration from %s\n"), cfgfilename);
1414 GNUNET_CONFIGURATION_destroy (cfg);
1415 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1418 peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1421 GNUNET_CONFIGURATION_destroy (cfg);
1422 hostkeys_unload (system);
1423 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1426 GNUNET_free (peer->main_binary);
1427 GNUNET_free (peer->args);
1428 GNUNET_asprintf (&binary, "gnunet-service-%s", service_name);
1429 libexec_binary = GNUNET_OS_get_libexec_binary_path (binary);
1430 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, service_name, "PREFIX", &peer->main_binary))
1433 GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1434 peer->args = strdup ("");
1437 peer->args = strdup (libexec_binary);
1439 GNUNET_free (libexec_binary);
1440 GNUNET_free (binary);
1441 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1443 GNUNET_TESTING_peer_destroy (peer);
1444 GNUNET_CONFIGURATION_destroy (cfg);
1445 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1452 GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1453 if ((NULL != peer->main_process) &&
1454 (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1456 GNUNET_TESTING_peer_destroy (peer);
1457 GNUNET_CONFIGURATION_destroy (cfg);
1458 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1461 GNUNET_TESTING_peer_destroy (peer);
1462 GNUNET_CONFIGURATION_destroy (cfg);
1463 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1469 * Sometimes we use the binary name to determine which specific
1470 * test to run. In those cases, the string after the last "_"
1471 * in 'argv[0]' specifies a string that determines the configuration
1472 * file or plugin to use.
1474 * This function returns the respective substring, taking care
1475 * of issues such as binaries ending in '.exe' on W32.
1477 * @param argv0 the name of the binary
1478 * @return string between the last '_' and the '.exe' (or the end of the string),
1479 * NULL if argv0 has no '_'
1482 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1484 size_t slen = strlen (argv0) + 1;
1489 memcpy (sbuf, argv0, slen);
1490 ret = strrchr (sbuf, '_');
1493 ret++; /* skip underscore */
1494 dot = strchr (ret, '.');
1497 return GNUNET_strdup (ret);
1501 /* end of testing.c */