2 This file is part of GNUnet
3 (C) 2008, 2009, 2012 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file testing/testing.c
23 * @brief convenience API for writing testcases for GNUnet
24 * Many testcases need to start and stop a peer/service
25 * and this library is supposed to make that easier
26 * for TESTCASES. Normal programs should always
27 * use functions from gnunet_{util,arm}_lib.h. This API is
28 * ONLY for writing testcases (or internal use of the testbed).
29 * @author Christian Grothoff
33 #include "gnunet_util_lib.h"
34 #include "gnunet_testing_lib-new.h"
36 #define LOG(kind,...) \
37 GNUNET_log_from (kind, "gnunettestingnew", __VA_ARGS__)
40 * Size of a hostkey when written to a file
42 #define HOSTKEYFILESIZE 914
45 * Lowest port used for GNUnet testing. Should be high enough to not
46 * conflict with other applications running on the hosts but be low
47 * enough to not conflict with client-ports (typically starting around
50 #define LOW_PORT 12000
53 * Highest port used for GNUnet testing. Should be low enough to not
54 * conflict with the port range for "local" ports (client apps; see
55 * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
57 #define HIGH_PORT 56000
61 * Handle for a system on which GNUnet peers are executed;
62 * a system is used for reserving unique paths and ports.
64 struct GNUNET_TESTING_System
67 * Prefix (i.e. "/tmp/gnunet-testing/") we prepend to each
72 * The hostname of the controller
77 * Hostkeys data, contains "HOSTKEYFILESIZE * total_hostkeys" bytes.
82 * memory map for 'hostkeys_data'.
84 struct GNUNET_DISK_MapHandle *map;
87 * File descriptor for the map.
89 struct GNUNET_DISK_FileHandle *map_fd;
92 * Bitmap where each TCP port that has already been reserved for
93 * some GNUnet peer is recorded. Note that we additionally need to
94 * test if a port is already in use by non-GNUnet components before
95 * assigning it to a peer/service. If we detect that a port is
96 * already in use, we also mark it in this bitmap. So all the bits
97 * that are zero merely indicate ports that MIGHT be available for
100 uint32_t reserved_tcp_ports[65536 / 32];
103 * Bitmap where each UDP port that has already been reserved for
104 * some GNUnet peer is recorded. Note that we additionally need to
105 * test if a port is already in use by non-GNUnet components before
106 * assigning it to a peer/service. If we detect that a port is
107 * already in use, we also mark it in this bitmap. So all the bits
108 * that are zero merely indicate ports that MIGHT be available for
111 uint32_t reserved_udp_ports[65536 / 32];
114 * Counter we use to make service home paths unique on this system;
115 * the full path consists of the tmppath and this number. Each
116 * UNIXPATH for a peer is also modified to include the respective
117 * path counter to ensure uniqueness. This field is incremented
118 * by one for each configured peer. Even if peers are destroyed,
119 * we never re-use path counters.
121 uint32_t path_counter;
124 * The number of hostkeys
126 uint32_t total_hostkeys;
131 * Handle for a GNUnet peer controlled by testing.
133 struct GNUNET_TESTING_Peer
136 * The TESTING system associated with this peer
138 struct GNUNET_TESTING_System *system;
141 * Path to the configuration file for this peer.
146 * Binary to be executed during 'GNUNET_TESTING_peer_start'.
147 * Typically 'gnunet-service-arm' (but can be set to a
148 * specific service by 'GNUNET_TESTING_service_run' if
154 * Handle to the running binary of the service, NULL if the
155 * peer/service is currently not running.
157 struct GNUNET_OS_Process *main_process;
160 * The keynumber of this peer's hostkey
167 * Testing includes a number of pre-created hostkeys for faster peer
168 * startup. This function loads such keys into memory from a file.
170 * @param system the testing system handle
171 * @return GNUNET_OK on success; GNUNET_SYSERR on error
174 hostkeys_load (struct GNUNET_TESTING_System *system)
180 GNUNET_assert (NULL == system->hostkeys_data);
181 data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
182 GNUNET_asprintf (&filename, "%s/testing_hostkeys.dat", data_dir);
183 GNUNET_free (data_dir);
185 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
187 LOG (GNUNET_ERROR_TYPE_ERROR,
188 _("Hostkeys file not found: %s\n"), filename);
189 GNUNET_free (filename);
190 return GNUNET_SYSERR;
192 /* Check hostkey file size, read entire thing into memory */
194 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
198 GNUNET_free (filename);
199 return GNUNET_SYSERR; /* File is empty */
201 if (0 != (fs % HOSTKEYFILESIZE))
203 LOG (GNUNET_ERROR_TYPE_ERROR,
204 _("Incorrect hostkey file format: %s\n"), filename);
205 GNUNET_free (filename);
206 return GNUNET_SYSERR;
208 system->map_fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
209 GNUNET_DISK_PERM_NONE);
210 if (NULL == system->map_fd)
212 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename);
213 GNUNET_free (filename);
214 return GNUNET_SYSERR;
216 system->total_hostkeys = fs / HOSTKEYFILESIZE;
217 system->hostkeys_data = GNUNET_DISK_file_map (system->map_fd,
219 GNUNET_DISK_MAP_TYPE_READ,
221 GNUNET_free (filename);
227 * Function to remove the loaded hostkeys
229 * @param system the testing system handle
232 hostkeys_unload (struct GNUNET_TESTING_System *system)
234 GNUNET_break (NULL != system->hostkeys_data);
235 system->hostkeys_data = NULL;
236 GNUNET_DISK_file_unmap (system->map);
238 GNUNET_DISK_file_close (system->map_fd);
239 system->map_fd = NULL;
240 system->hostkeys_data = NULL;
241 system->total_hostkeys = 0;
246 * Create a system handle. There must only be one system
247 * handle per operating system.
249 * @param testdir only the directory name without any path. This is used for
250 * all service homes; the directory will be created in a temporary
251 * location depending on the underlying OS
253 * @param controller hostname of the controlling host,
254 * service configurations are modified to allow
255 * control connections from this host; can be NULL
256 * @return handle to this system, NULL on error
258 struct GNUNET_TESTING_System *
259 GNUNET_TESTING_system_create (const char *testdir,
260 const char *controller)
262 struct GNUNET_TESTING_System *system;
264 GNUNET_assert (NULL != testdir);
265 system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
266 system->tmppath = GNUNET_DISK_mkdtemp (testdir);
267 if (NULL == system->tmppath)
269 GNUNET_free (system);
272 if (NULL != controller)
273 system->controller = GNUNET_strdup (controller);
274 if (GNUNET_OK != hostkeys_load (system))
276 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
284 * Free system resources.
286 * @param system system to be freed
287 * @param remove_paths should the 'testdir' and all subdirectories
288 * be removed (clean up on shutdown)?
291 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
294 if (NULL != system->hostkeys_data)
295 hostkeys_unload (system);
296 if (GNUNET_YES == remove_paths)
297 GNUNET_DISK_directory_remove (system->tmppath);
298 GNUNET_free (system->tmppath);
299 GNUNET_free_non_null (system->controller);
300 GNUNET_free (system);
305 * Reserve a TCP or UDP port for a peer.
307 * @param system system to use for reservation tracking
308 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
309 * @return 0 if no free port was available
312 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system,
315 struct GNUNET_NETWORK_Handle *socket;
316 struct addrinfo hint;
317 struct addrinfo *ret;
318 uint32_t *port_buckets;
327 FIXME: Instead of using getaddrinfo we should try to determine the port
328 status by the following heurestics.
330 On systems which support both IPv4 and IPv6, only ports open on both
331 address families are considered open.
332 On system with either IPv4 or IPv6. A port is considered open if it's
333 open in the respective address family
335 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
336 hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM;
337 hint.ai_protocol = 0;
340 hint.ai_canonname = NULL;
342 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
343 port_buckets = (GNUNET_YES == is_tcp) ?
344 system->reserved_tcp_ports : system->reserved_udp_ports;
345 for (index = (LOW_PORT / 32) + 1; index < (HIGH_PORT / 32); index++)
347 xor_image = (UINT32_MAX ^ port_buckets[index]);
348 if (0 == xor_image) /* Ports in the bucket are full */
353 if (0 == ((xor_image >> pos) & 1U))
358 open_port = (index * 32) + pos;
359 GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
361 GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
362 GNUNET_free (open_port_str);
363 socket = GNUNET_NETWORK_socket_create (ret->ai_family,
364 (GNUNET_YES == is_tcp) ?
365 SOCK_STREAM : SOCK_DGRAM,
367 GNUNET_assert (NULL != socket);
368 bind_status = GNUNET_NETWORK_socket_bind (socket,
372 GNUNET_NETWORK_socket_close (socket);
374 port_buckets[index] |= (1U << pos); /* Set the port bit */
375 if (GNUNET_OK == bind_status)
377 LOG (GNUNET_ERROR_TYPE_DEBUG,
378 "Found a free port %u\n", (unsigned int) open_port);
389 * Release reservation of a TCP or UDP port for a peer
390 * (used during GNUNET_TESTING_peer_destroy).
392 * @param system system to use for reservation tracking
393 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
394 * @param port reserved port to release
397 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
401 uint32_t *port_buckets;
405 port_buckets = (GNUNET_YES == is_tcp) ?
406 system->reserved_tcp_ports : system->reserved_udp_ports;
409 LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
410 if (0 == (port_buckets[bucket] & (1U << pos)))
412 GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
415 port_buckets[bucket] &= ~(1U << pos);
420 * Reserve a SERVICEHOME path for a peer.
422 * @param system system to use for reservation tracking
423 * @return NULL on error, otherwise fresh unique path to use
424 * as the servicehome for the peer; must be freed by the caller
428 reserve_path (struct GNUNET_TESTING_System *system)
432 GNUNET_asprintf (&reserved_path,
433 "%s/%u", system->tmppath, system->path_counter++);
434 return reserved_path;
439 * Testing includes a number of pre-created hostkeys for
440 * faster peer startup. This function can be used to
441 * access the n-th key of those pre-created hostkeys; note
442 * that these keys are ONLY useful for testing and not
443 * secure as the private keys are part of the public
444 * GNUnet source code.
446 * This is primarily a helper function used internally
447 * by 'GNUNET_TESTING_peer_configure'.
449 * @param system the testing system handle
450 * @param key_number desired pre-created hostkey to obtain
451 * @param id set to the peer's identity (hash of the public
452 * key; if NULL, GNUNET_SYSERR is returned immediately
453 * @return NULL on error (not enough keys)
455 struct GNUNET_CRYPTO_RsaPrivateKey *
456 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
458 struct GNUNET_PeerIdentity *id)
460 struct GNUNET_CRYPTO_RsaPrivateKey *private_key;
461 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
463 if ((NULL == id) || (NULL == system->hostkeys_data))
465 if (key_number >= system->total_hostkeys)
467 LOG (GNUNET_ERROR_TYPE_ERROR,
468 _("Key number %u does not exist\n"), key_number);
471 private_key = GNUNET_CRYPTO_rsa_decode_key (system->hostkeys_data +
472 (key_number * HOSTKEYFILESIZE),
474 if (NULL == private_key)
476 LOG (GNUNET_ERROR_TYPE_ERROR,
477 _("Error while decoding key %u\n"), key_number);
480 GNUNET_CRYPTO_rsa_key_get_public (private_key, &public_key);
481 GNUNET_CRYPTO_hash (&public_key,
482 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
489 * Structure for holding data to build new configurations from a configuration
495 * The system for which we are building configurations
497 struct GNUNET_TESTING_System *system;
500 * The configuration we are building
502 struct GNUNET_CONFIGURATION_Handle *cfg;
505 * The customized service home path for this peer
510 * build status - to signal error while building a configuration
517 * Function to iterate over options. Copies
518 * the options to the target configuration,
519 * updating PORT values as needed.
521 * @param cls the UpdateContext
522 * @param section name of the section
523 * @param option name of the option
524 * @param value value of the option
527 update_config (void *cls, const char *section, const char *option,
530 struct UpdateContext *uc = cls;
534 char *single_variable;
535 char *per_host_variable;
536 unsigned long long num_per_host;
539 if (GNUNET_OK != uc->status)
541 if (! ((0 == strcmp (option, "PORT"))
542 || (0 == strcmp (option, "UNIXPATH"))
543 || (0 == strcmp (option, "HOSTNAME"))))
545 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
546 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
547 if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
551 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
554 /* FIXME: What about UDP? */
555 new_port = GNUNET_TESTING_reserve_port (uc->system, GNUNET_YES);
558 uc->status = GNUNET_SYSERR;
561 GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
564 else if ((ival != 0) &&
566 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
568 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
572 /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
573 /* ival + ctx->fdnum % num_per_host); */
575 GNUNET_break (0); /* FIXME */
578 if (0 == strcmp (option, "UNIXPATH"))
581 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
584 GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock",
585 uc->service_home, section);
588 else if ((GNUNET_YES ==
589 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
594 GNUNET_break(0); /* FIXME */
597 if ((0 == strcmp (option, "HOSTNAME")) && (NULL != uc->system->controller))
599 value = uc->system->controller;
601 GNUNET_free (single_variable);
602 GNUNET_free (per_host_variable);
603 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
608 * Section iterator to set ACCEPT_FROM in all sections
610 * @param cls the UpdateContext
611 * @param section name of the section
614 update_config_sections (void *cls,
617 struct UpdateContext *uc = cls;
621 char *orig_allowed_hosts;
628 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
629 "TESTING_IGNORE_KEYS"))
633 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section,
634 "TESTING_IGNORE_KEYS", &val));
636 for (ikeys_cnt = 0; NULL != (ptr = strstr (ptr, ";")); ikeys_cnt++)
642 ikeys = GNUNET_malloc ((sizeof (char *)) * ikeys_cnt);
644 for (key = 0; key < ikeys_cnt; key++)
647 ptr = strstr (ptr, ";");
655 for (key = 0; key < ikeys_cnt; key++)
657 if (NULL != strstr (ikeys[key], "ADVERTISED_PORT"))
660 if ((key == ikeys_cnt) &&
661 (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
665 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "PORT", &ptr))
667 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section,
668 "ADVERTISED_PORT", ptr);
672 for (key = 0; key < ikeys_cnt; key++)
674 if (NULL != strstr (ikeys[key], "ACCEPT_FROM"))
683 GNUNET_free_non_null (val);
685 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "ACCEPT_FROM",
686 &orig_allowed_hosts))
688 orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
690 if (NULL == uc->system->controller)
691 allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
693 GNUNET_asprintf (&allowed_hosts, "%s%s;", orig_allowed_hosts,
694 uc->system->controller);
695 GNUNET_free (orig_allowed_hosts);
696 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, "ACCEPT_FROM",
698 GNUNET_free (allowed_hosts);
703 * Create a new configuration using the given configuration
704 * as a template; ports and paths will be modified to select
705 * available ports on the local system. If we run
706 * out of "*port" numbers, return SYSERR.
708 * This is primarily a helper function used internally
709 * by 'GNUNET_TESTING_peer_configure'.
711 * @param system system to use to coordinate resource usage
712 * @param cfg template configuration to update
713 * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
714 * be incomplete and should not be used there upon
717 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
718 struct GNUNET_CONFIGURATION_Handle *cfg)
720 struct UpdateContext uc;
721 char *default_config;
725 uc.status = GNUNET_OK;
726 GNUNET_asprintf (&uc.service_home, "%s/%u", system->tmppath,
727 system->path_counter++);
728 GNUNET_asprintf (&default_config, "%s/config", uc.service_home);
729 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
731 GNUNET_free (default_config);
732 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME",
734 /* make PORTs and UNIXPATHs unique */
735 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
736 /* allow connections to services from system controller host */
737 GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
738 /* enable loopback-based connections between peers */
739 GNUNET_CONFIGURATION_set_value_string (cfg,
741 "USE_LOCALADDR", "YES");
742 GNUNET_free (uc.service_home);
748 * Configure a GNUnet peer. GNUnet must be installed on the local
749 * system and available in the PATH.
751 * @param system system to use to coordinate resource usage
752 * @param cfg configuration to use; will be UPDATED (to reflect needed
753 * changes in port numbers and paths)
754 * @param key_number number of the hostkey to use for the peer
755 * @param id identifier for the daemon, will be set, can be NULL
756 * @param emsg set to freshly allocated error message (set to NULL on success),
758 * @return handle to the peer, NULL on error
760 struct GNUNET_TESTING_Peer *
761 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
762 struct GNUNET_CONFIGURATION_Handle *cfg,
764 struct GNUNET_PeerIdentity *id,
767 struct GNUNET_TESTING_Peer *peer;
768 struct GNUNET_DISK_FileHandle *fd;
770 char hostkey_filename[128];
771 char *config_filename;
773 struct GNUNET_CRYPTO_RsaPrivateKey *pk;
777 if (GNUNET_OK != GNUNET_TESTING_configuration_create (system, cfg))
779 GNUNET_asprintf (&emsg_,
780 _("Failed to create configuration for peer (not enough free ports?)\n"));
781 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
788 if (key_number >= system->total_hostkeys)
790 GNUNET_asprintf (&emsg_,
791 _("You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"),
792 (unsigned int) system->total_hostkeys);
793 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
802 (NULL == (pk = GNUNET_TESTING_hostkey_get (system, key_number, id))))
804 GNUNET_asprintf (&emsg_,
805 _("Failed to initialize hostkey for peer %u\n"),
806 (unsigned int) key_number);
807 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
815 GNUNET_CRYPTO_rsa_key_free (pk);
816 GNUNET_assert (GNUNET_OK ==
817 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
820 GNUNET_snprintf (hostkey_filename, sizeof (hostkey_filename), "%s/.hostkey",
822 GNUNET_free (service_home);
823 fd = GNUNET_DISK_file_open (hostkey_filename,
824 GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
825 GNUNET_DISK_PERM_USER_READ
826 | GNUNET_DISK_PERM_USER_WRITE);
832 if (HOSTKEYFILESIZE !=
833 GNUNET_DISK_file_write (fd, system->hostkeys_data
834 + (key_number * HOSTKEYFILESIZE),
837 GNUNET_asprintf (&emsg_,
838 _("Failed to write hostkey file for peer %u: %s\n"),
839 (unsigned int) key_number,
841 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
846 GNUNET_DISK_file_close (fd);
849 GNUNET_DISK_file_close (fd);
850 GNUNET_assert (GNUNET_OK ==
851 GNUNET_CONFIGURATION_get_value_string
852 (cfg, "PATHS", "DEFAULTCONFIG", &config_filename));
853 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
855 GNUNET_asprintf (&emsg_,
856 _("Failed to write configuration file `%s' for peer %u: %s\n"),
858 (unsigned int) key_number,
860 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
865 GNUNET_free (config_filename);
868 peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
869 peer->cfgfile = config_filename; /* Free in peer_destroy */
870 peer->main_binary = GNUNET_strdup ("gnunet-service-arm");
871 peer->system = system;
872 peer->key_number = key_number;
878 * Obtain the peer identity from a peer handle.
880 * @param peer peer handle for which we want the peer's identity
881 * @param id identifier for the daemon, will be set
884 GNUNET_TESTING_peer_get_identity (const struct GNUNET_TESTING_Peer *peer,
885 struct GNUNET_PeerIdentity *id)
887 GNUNET_CRYPTO_rsa_key_free (GNUNET_TESTING_hostkey_get (peer->system,
896 * @param peer peer to start
897 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
900 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
902 if (NULL != peer->main_process)
905 return GNUNET_SYSERR;
907 GNUNET_assert (NULL != peer->cfgfile);
908 peer->main_process = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL,
914 if (NULL == peer->main_process)
916 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
917 _("Failed to start `%s': %s\n"),
920 return GNUNET_SYSERR;
929 * @param peer peer to stop
930 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer not running)
933 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
935 if (NULL == peer->main_process)
938 return GNUNET_SYSERR;
940 (void) GNUNET_OS_process_kill (peer->main_process, SIGTERM);
941 GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (peer->main_process));
942 GNUNET_OS_process_destroy (peer->main_process);
943 peer->main_process = NULL;
949 * Destroy the peer. Releases resources locked during peer configuration.
950 * If the peer is still running, it will be stopped AND a warning will be
951 * printed (users of the API should stop the peer explicitly first).
953 * @param peer peer to destroy
956 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
958 if (NULL != peer->main_process)
961 GNUNET_TESTING_peer_stop (peer);
963 GNUNET_free (peer->cfgfile);
964 GNUNET_free (peer->main_binary);
970 * Start a single peer and run a test using the testing library.
971 * Starts a peer using the given configuration and then invokes the
972 * given callback. This function ALSO initializes the scheduler loop
973 * and should thus be called directly from "main". The testcase
974 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
976 * @param testdir only the directory name without any path. This is used for
977 * all service homes; the directory will be created in a temporary
978 * location depending on the underlying OS
979 * @param cfgfilename name of the configuration file to use;
980 * use NULL to only run with defaults
981 * @param tm main function of the testcase
982 * @param tm_cls closure for 'tm'
983 * @return 0 on success, 1 on error
986 GNUNET_TESTING_peer_run (const char *testdir,
987 const char *cfgfilename,
988 GNUNET_TESTING_TestMain tm,
991 return GNUNET_TESTING_service_run (testdir, "arm",
992 cfgfilename, tm, tm_cls);
997 * Structure for holding service data
999 struct ServiceContext
1002 * The configuration of the peer in which the service is run
1004 const struct GNUNET_CONFIGURATION_Handle *cfg;
1007 * Callback to signal service startup
1009 GNUNET_TESTING_TestMain tm;
1012 * The peer in which the service is run.
1014 struct GNUNET_TESTING_Peer *peer;
1017 * Closure for the above callback
1024 * Callback to be called when SCHEDULER has been started
1026 * @param cls the ServiceContext
1027 * @param tc the TaskContext
1030 service_run_main (void *cls,
1031 const struct GNUNET_SCHEDULER_TaskContext *tc)
1033 struct ServiceContext *sc = cls;
1035 sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1040 * Start a single service (no ARM, except of course if the given
1041 * service name is 'arm') and run a test using the testing library.
1042 * Starts a service using the given configuration and then invokes the
1043 * given callback. This function ALSO initializes the scheduler loop
1044 * and should thus be called directly from "main". The testcase
1045 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
1047 * This function is useful if the testcase is for a single service
1048 * and if that service doesn't itself depend on other services.
1050 * @param testdir only the directory name without any path. This is used for
1051 * all service homes; the directory will be created in a temporary
1052 * location depending on the underlying OS
1053 * @param service_name name of the service to run
1054 * @param cfgfilename name of the configuration file to use;
1055 * use NULL to only run with defaults
1056 * @param tm main function of the testcase
1057 * @param tm_cls closure for 'tm'
1058 * @return 0 on success, 1 on error
1061 GNUNET_TESTING_service_run (const char *testdir,
1062 const char *service_name,
1063 const char *cfgfilename,
1064 GNUNET_TESTING_TestMain tm,
1067 struct ServiceContext sc;
1068 struct GNUNET_TESTING_System *system;
1069 struct GNUNET_TESTING_Peer *peer;
1070 struct GNUNET_CONFIGURATION_Handle *cfg;
1072 GNUNET_log_setup (testdir, "WARNING", NULL);
1073 system = GNUNET_TESTING_system_create (testdir, "127.0.0.1");
1076 cfg = GNUNET_CONFIGURATION_create ();
1077 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1079 LOG (GNUNET_ERROR_TYPE_ERROR,
1080 _("Failed to load configuration from %s\n"), cfgfilename);
1081 GNUNET_CONFIGURATION_destroy (cfg);
1082 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1085 peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1088 GNUNET_CONFIGURATION_destroy (cfg);
1089 hostkeys_unload (system);
1090 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1093 GNUNET_free (peer->main_binary);
1094 GNUNET_asprintf (&peer->main_binary, "gnunet-service-%s", service_name);
1095 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1097 GNUNET_TESTING_peer_destroy (peer);
1098 GNUNET_CONFIGURATION_destroy (cfg);
1099 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1106 GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1107 if ((NULL != peer->main_process) &&
1108 (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1110 GNUNET_TESTING_peer_destroy (peer);
1111 GNUNET_CONFIGURATION_destroy (cfg);
1112 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1115 GNUNET_TESTING_peer_destroy (peer);
1116 GNUNET_CONFIGURATION_destroy (cfg);
1117 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1123 * Sometimes we use the binary name to determine which specific
1124 * test to run. In those cases, the string after the last "_"
1125 * in 'argv[0]' specifies a string that determines the configuration
1126 * file or plugin to use.
1128 * This function returns the respective substring, taking care
1129 * of issues such as binaries ending in '.exe' on W32.
1131 * @param argv0 the name of the binary
1132 * @return string between the last '_' and the '.exe' (or the end of the string),
1133 * NULL if argv0 has no '_'
1136 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1138 size_t slen = strlen (argv0) + 1;
1143 memcpy (sbuf, argv0, slen);
1144 ret = strrchr (sbuf, '_');
1147 ret++; /* skip underscore */
1148 dot = strchr (ret, '.');
1151 return GNUNET_strdup (ret);
1155 /* end of testing.c */