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__)
41 * Size of a hostkey when written to a file
43 #define HOSTKEYFILESIZE 914
47 * Handle for a system on which GNUnet peers are executed;
48 * a system is used for reserving unique paths and ports.
50 struct GNUNET_TESTING_System
53 * Prefix (i.e. "/tmp/gnunet-testing/") we prepend to each
59 * The hostname of the controller
64 * Hostkeys data, contains "HOSTKEYFILESIZE * total_hostkeys" bytes.
69 * memory map for 'hostkeys_data'.
71 struct GNUNET_DISK_MapHandle *map;
74 * File descriptor for the map.
76 struct GNUNET_DISK_FileHandle *map_fd;
79 * Bitmap where each TCP port that has already been reserved for
80 * some GNUnet peer is recorded. Note that we additionally need to
81 * test if a port is already in use by non-GNUnet components before
82 * assigning it to a peer/service. If we detect that a port is
83 * already in use, we also mark it in this bitmap. So all the bits
84 * that are zero merely indicate ports that MIGHT be available for
87 uint32_t reserved_tcp_ports[65536 / 32];
90 * Bitmap where each UDP port that has already been reserved for
91 * some GNUnet peer is recorded. Note that we additionally need to
92 * test if a port is already in use by non-GNUnet components before
93 * assigning it to a peer/service. If we detect that a port is
94 * already in use, we also mark it in this bitmap. So all the bits
95 * that are zero merely indicate ports that MIGHT be available for
98 uint32_t reserved_udp_ports[65536 / 32];
101 * Counter we use to make service home paths unique on this system;
102 * the full path consists of the tmppath and this number. Each
103 * UNIXPATH for a peer is also modified to include the respective
104 * path counter to ensure uniqueness. This field is incremented
105 * by one for each configured peer. Even if peers are destroyed,
106 * we never re-use path counters.
108 uint32_t path_counter;
111 * The number of hostkeys
113 uint32_t total_hostkeys;
118 * Handle for a GNUnet peer controlled by testing.
120 struct GNUNET_TESTING_Peer
124 * Path to the configuration file for this peer.
129 * Binary to be executed during 'GNUNET_TESTING_peer_start'.
130 * Typically 'gnunet-service-arm' (but can be set to a
131 * specific service by 'GNUNET_TESTING_service_run' if
137 * Handle to the running binary of the service, NULL if the
138 * peer/service is currently not running.
140 struct GNUNET_OS_Process *main_process;
145 * Lowest port used for GNUnet testing. Should be high enough to not
146 * conflict with other applications running on the hosts but be low
147 * enough to not conflict with client-ports (typically starting around
150 #define LOW_PORT 12000
154 * Highest port used for GNUnet testing. Should be low enough to not
155 * conflict with the port range for "local" ports (client apps; see
156 * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
158 #define HIGH_PORT 56000
162 * Testing includes a number of pre-created hostkeys for faster peer
163 * startup. This function loads such keys into memory from a file.
165 * @param system the testing system handle
166 * @return GNUNET_OK on success; GNUNET_SYSERR on error
169 hostkeys_load (struct GNUNET_TESTING_System *system)
175 GNUNET_assert (NULL == system->hostkeys_data);
176 data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
177 GNUNET_asprintf (&filename, "%s/testing_hostkeys.dat", data_dir);
178 GNUNET_free (data_dir);
180 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
182 LOG (GNUNET_ERROR_TYPE_ERROR,
183 _("Hostkeys file not found: %s\n"), filename);
184 GNUNET_free (filename);
185 return GNUNET_SYSERR;
187 /* Check hostkey file size, read entire thing into memory */
189 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
193 GNUNET_free (filename);
194 return GNUNET_SYSERR; /* File is empty */
196 if (0 != (fs % HOSTKEYFILESIZE))
198 LOG (GNUNET_ERROR_TYPE_ERROR,
199 _("Incorrect hostkey file format: %s\n"), filename);
200 GNUNET_free (filename);
201 return GNUNET_SYSERR;
203 system->map_fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
204 GNUNET_DISK_PERM_NONE);
205 if (NULL == system->map_fd)
207 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename);
208 GNUNET_free (filename);
209 return GNUNET_SYSERR;
211 system->total_hostkeys = fs / HOSTKEYFILESIZE;
212 system->hostkeys_data = GNUNET_DISK_file_map (system->map_fd,
214 GNUNET_DISK_MAP_TYPE_READ,
216 GNUNET_free (filename);
222 * Function to remove the loaded hostkeys
224 * @param system the testing system handle
227 hostkeys_unload (struct GNUNET_TESTING_System *system)
229 GNUNET_break (NULL != system->hostkeys_data);
230 system->hostkeys_data = NULL;
231 GNUNET_DISK_file_unmap (system->map);
233 GNUNET_DISK_file_close (system->map_fd);
234 system->map_fd = NULL;
235 system->hostkeys_data = NULL;
236 system->total_hostkeys = 0;
241 * Create a system handle. There must only be one system
242 * handle per operating system.
244 * @param tmppath prefix path to use for all service homes
245 * @param controller hostname of the controlling host,
246 * service configurations are modified to allow
247 * control connections from this host; can be NULL
248 * @return handle to this system, NULL on error
250 struct GNUNET_TESTING_System *
251 GNUNET_TESTING_system_create (const char *tmppath,
252 const char *controller)
254 struct GNUNET_TESTING_System *system;
256 GNUNET_assert (NULL != tmppath);
257 system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
258 system->tmppath = GNUNET_DISK_mkdtemp (tmppath);
259 if (NULL == system->tmppath)
261 GNUNET_free (system);
264 if (NULL != controller)
265 system->controller = GNUNET_strdup (controller);
266 if (GNUNET_OK != hostkeys_load (system))
268 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
276 * Free system resources.
278 * @param system system to be freed
279 * @param remove_paths should the 'tmppath' and all subdirectories
280 * be removed (clean up on shutdown)?
283 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
286 if (NULL != system->hostkeys_data)
287 hostkeys_unload (system);
288 if (GNUNET_YES == remove_paths)
289 GNUNET_DISK_directory_remove (system->tmppath);
290 GNUNET_free (system->tmppath);
291 GNUNET_free_non_null (system->controller);
292 GNUNET_free (system);
297 * Reserve a TCP or UDP port for a peer.
299 * @param system system to use for reservation tracking
300 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
301 * @return 0 if no free port was available
304 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system,
307 struct GNUNET_NETWORK_Handle *socket;
308 struct addrinfo hint;
309 struct addrinfo *ret;
310 uint32_t *port_buckets;
319 FIXME: Instead of using getaddrinfo we should try to determine the port
320 status by the following heurestics.
322 On systems which support both IPv4 and IPv6, only ports open on both
323 address families are considered open.
324 On system with either IPv4 or IPv6. A port is considered open if it's
325 open in the respective address family
327 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
328 hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM;
329 hint.ai_protocol = 0;
332 hint.ai_canonname = NULL;
334 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
335 port_buckets = (GNUNET_YES == is_tcp) ?
336 system->reserved_tcp_ports : system->reserved_udp_ports;
337 for (index = (LOW_PORT / 32) + 1; index < (HIGH_PORT / 32); index++)
339 xor_image = (UINT32_MAX ^ port_buckets[index]);
340 if (0 == xor_image) /* Ports in the bucket are full */
345 if (0 == ((xor_image >> pos) & 1U))
350 open_port = (index * 32) + pos;
351 GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
353 GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
354 GNUNET_free (open_port_str);
355 socket = GNUNET_NETWORK_socket_create (ret->ai_family,
356 (GNUNET_YES == is_tcp) ?
357 SOCK_STREAM : SOCK_DGRAM,
359 GNUNET_assert (NULL != socket);
360 bind_status = GNUNET_NETWORK_socket_bind (socket,
364 GNUNET_NETWORK_socket_close (socket);
366 port_buckets[index] |= (1U << pos); /* Set the port bit */
367 if (GNUNET_OK == bind_status)
369 LOG (GNUNET_ERROR_TYPE_DEBUG,
370 "Found a free port %u\n", (unsigned int) open_port);
381 * Release reservation of a TCP or UDP port for a peer
382 * (used during GNUNET_TESTING_peer_destroy).
384 * @param system system to use for reservation tracking
385 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
386 * @param port reserved port to release
389 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
393 uint32_t *port_buckets;
397 port_buckets = (GNUNET_YES == is_tcp) ?
398 system->reserved_tcp_ports : system->reserved_udp_ports;
401 LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
402 if (0 == (port_buckets[bucket] & (1U << pos)))
404 GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
407 port_buckets[bucket] &= ~(1U << pos);
412 * Reserve a SERVICEHOME path for a peer.
414 * @param system system to use for reservation tracking
415 * @return NULL on error, otherwise fresh unique path to use
416 * as the servicehome for the peer; must be freed by the caller
420 reserve_path (struct GNUNET_TESTING_System *system)
424 GNUNET_asprintf (&reserved_path,
425 "%s/%u", system->tmppath, system->path_counter++);
426 return reserved_path;
431 * Testing includes a number of pre-created hostkeys for
432 * faster peer startup. This function can be used to
433 * access the n-th key of those pre-created hostkeys; note
434 * that these keys are ONLY useful for testing and not
435 * secure as the private keys are part of the public
436 * GNUnet source code.
438 * This is primarily a helper function used internally
439 * by 'GNUNET_TESTING_peer_configure'.
441 * @param system the testing system handle
442 * @param key_number desired pre-created hostkey to obtain
443 * @param id set to the peer's identity (hash of the public
444 * key; if NULL, GNUNET_SYSERR is returned immediately
445 * @return GNUNET_SYSERR on error (not enough keys)
448 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
450 struct GNUNET_PeerIdentity *id)
452 struct GNUNET_CRYPTO_RsaPrivateKey *private_key;
453 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
455 if ((NULL == id) || (NULL == system->hostkeys_data))
456 return GNUNET_SYSERR;
457 if (key_number >= system->total_hostkeys)
459 LOG (GNUNET_ERROR_TYPE_ERROR,
460 _("Key number %u does not exist\n"), key_number);
461 return GNUNET_SYSERR;
463 private_key = GNUNET_CRYPTO_rsa_decode_key (system->hostkeys_data +
464 (key_number * HOSTKEYFILESIZE),
466 if (NULL == private_key)
468 LOG (GNUNET_ERROR_TYPE_ERROR,
469 _("Error while decoding key %u\n"), key_number);
470 return GNUNET_SYSERR;
472 GNUNET_CRYPTO_rsa_key_get_public (private_key, &public_key);
473 GNUNET_CRYPTO_hash (&public_key,
474 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
476 GNUNET_CRYPTO_rsa_key_free (private_key);
482 * Structure for holding data to build new configurations from a configuration
488 * The system for which we are building configurations
490 struct GNUNET_TESTING_System *system;
493 * The configuration we are building
495 struct GNUNET_CONFIGURATION_Handle *cfg;
498 * The customized service home path for this peer
503 * build status - to signal error while building a configuration
510 * Function to iterate over options. Copies
511 * the options to the target configuration,
512 * updating PORT values as needed.
514 * @param cls the UpdateContext
515 * @param section name of the section
516 * @param option name of the option
517 * @param value value of the option
520 update_config (void *cls, const char *section, const char *option,
523 struct UpdateContext *uc = cls;
527 char *single_variable;
528 char *per_host_variable;
529 unsigned long long num_per_host;
532 if (GNUNET_OK != uc->status)
534 if (! ((0 == strcmp (option, "PORT"))
535 || (0 == strcmp (option, "UNIXPATH"))
536 || (0 == strcmp (option, "HOSTNAME"))))
538 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
539 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
540 if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
544 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
547 /* FIXME: What about UDP? */
548 new_port = GNUNET_TESTING_reserve_port (uc->system, GNUNET_YES);
551 uc->status = GNUNET_SYSERR;
554 GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
557 else if ((ival != 0) &&
559 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
561 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
565 /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
566 /* ival + ctx->fdnum % num_per_host); */
568 GNUNET_break (0); /* FIXME */
571 if (0 == strcmp (option, "UNIXPATH"))
574 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
577 GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock",
578 uc->service_home, section);
581 else if ((GNUNET_YES ==
582 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
587 GNUNET_break(0); /* FIXME */
590 if ((0 == strcmp (option, "HOSTNAME")) && (NULL != uc->system->controller))
592 value = uc->system->controller;
594 GNUNET_free (single_variable);
595 GNUNET_free (per_host_variable);
596 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
601 * Section iterator to set ACCEPT_FROM in all sections
603 * @param cls the UpdateContext
604 * @param section name of the section
607 update_config_sections (void *cls,
610 struct UpdateContext *uc = cls;
611 char *orig_allowed_hosts;
615 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "ACCEPT_FROM",
616 &orig_allowed_hosts))
618 orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
620 if (NULL == uc->system->controller)
621 allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
623 GNUNET_asprintf (&allowed_hosts, "%s%s;", orig_allowed_hosts,
624 uc->system->controller);
625 GNUNET_free (orig_allowed_hosts);
626 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, "ACCEPT_FROM",
628 GNUNET_free (allowed_hosts);
633 * Create a new configuration using the given configuration
634 * as a template; ports and paths will be modified to select
635 * available ports on the local system. If we run
636 * out of "*port" numbers, return SYSERR.
638 * This is primarily a helper function used internally
639 * by 'GNUNET_TESTING_peer_configure'.
641 * @param system system to use to coordinate resource usage
642 * @param cfg template configuration to update
643 * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
644 * be incomplete and should not be used there upon
647 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
648 struct GNUNET_CONFIGURATION_Handle *cfg)
650 struct UpdateContext uc;
651 char *default_config;
655 uc.status = GNUNET_OK;
656 GNUNET_asprintf (&uc.service_home, "%s/%u", system->tmppath,
657 system->path_counter++);
658 GNUNET_asprintf (&default_config, "%s/config", uc.service_home);
659 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
661 GNUNET_free (default_config);
662 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME",
664 /* make PORTs and UNIXPATHs unique */
665 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
666 /* allow connections to services from system controller host */
667 GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
668 /* enable loopback-based connections between peers */
669 GNUNET_CONFIGURATION_set_value_string (cfg,
671 "USE_LOCALADDR", "YES");
672 GNUNET_free (uc.service_home);
678 * Configure a GNUnet peer. GNUnet must be installed on the local
679 * system and available in the PATH.
681 * @param system system to use to coordinate resource usage
682 * @param cfg configuration to use; will be UPDATED (to reflect needed
683 * changes in port numbers and paths)
684 * @param key_number number of the hostkey to use for the peer
685 * @param id identifier for the daemon, will be set, can be NULL
686 * @param emsg set to error message (set to NULL on success), can be NULL
687 * @return handle to the peer, NULL on error
689 struct GNUNET_TESTING_Peer *
690 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
691 struct GNUNET_CONFIGURATION_Handle *cfg,
693 struct GNUNET_PeerIdentity *id,
696 struct GNUNET_TESTING_Peer *peer;
697 struct GNUNET_DISK_FileHandle *fd;
699 char hostkey_filename[128];
700 char *config_filename;
705 if (GNUNET_OK != GNUNET_TESTING_configuration_create (system, cfg))
707 GNUNET_asprintf (&emsg_,
708 _("Failed to create configuration for peer (not enough free ports?)\n"));
709 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
716 if (key_number >= system->total_hostkeys)
718 GNUNET_asprintf (&emsg_,
719 _("You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"),
720 (unsigned int) system->total_hostkeys);
721 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
729 (GNUNET_SYSERR == GNUNET_TESTING_hostkey_get (system, key_number, id)))
731 GNUNET_asprintf (&emsg_,
732 _("Failed to initialize hostkey for peer %u\n"),
733 (unsigned int) key_number);
734 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
741 GNUNET_assert (GNUNET_OK ==
742 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
745 GNUNET_snprintf (hostkey_filename, sizeof (hostkey_filename), "%s/.hostkey",
747 GNUNET_free (service_home);
748 fd = GNUNET_DISK_file_open (hostkey_filename,
749 GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
750 GNUNET_DISK_PERM_USER_READ
751 | GNUNET_DISK_PERM_USER_WRITE);
757 if (HOSTKEYFILESIZE !=
758 GNUNET_DISK_file_write (fd, system->hostkeys_data
759 + (key_number * HOSTKEYFILESIZE),
762 GNUNET_asprintf (&emsg_,
763 _("Failed to write hostkey file for peer %u: %s\n"),
764 (unsigned int) key_number,
766 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
771 GNUNET_DISK_file_close (fd);
774 GNUNET_DISK_file_close (fd);
775 GNUNET_assert (GNUNET_OK ==
776 GNUNET_CONFIGURATION_get_value_string
777 (cfg, "PATHS", "DEFAULTCONFIG", &config_filename));
778 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
780 GNUNET_asprintf (&emsg_,
781 _("Failed to write configuration file `%s' for peer %u: %s\n"),
783 (unsigned int) key_number,
785 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
790 GNUNET_free (config_filename);
793 peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
794 peer->cfgfile = config_filename; /* Free in peer_destroy */
795 peer->main_binary = GNUNET_strdup ("gnunet-service-arm");
803 * @param peer peer to start
804 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
807 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
809 if (NULL != peer->main_process)
812 return GNUNET_SYSERR;
814 GNUNET_assert (NULL != peer->cfgfile);
815 peer->main_process = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL,
821 if (NULL == peer->main_process)
823 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
824 _("Failed to start `%s': %s\n"),
827 return GNUNET_SYSERR;
836 * @param peer peer to stop
837 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer not running)
840 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
842 if (NULL == peer->main_process)
845 return GNUNET_SYSERR;
847 (void) GNUNET_OS_process_kill (peer->main_process, SIGTERM);
848 GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (peer->main_process));
849 GNUNET_OS_process_destroy (peer->main_process);
850 peer->main_process = NULL;
856 * Destroy the peer. Releases resources locked during peer configuration.
857 * If the peer is still running, it will be stopped AND a warning will be
858 * printed (users of the API should stop the peer explicitly first).
860 * @param peer peer to destroy
863 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
865 if (NULL != peer->main_process)
868 GNUNET_TESTING_peer_stop (peer);
870 GNUNET_free (peer->cfgfile);
871 GNUNET_free (peer->main_binary);
877 * Start a single peer and run a test using the testing library.
878 * Starts a peer using the given configuration and then invokes the
879 * given callback. This function ALSO initializes the scheduler loop
880 * and should thus be called directly from "main". The testcase
881 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
883 * @param tmppath path for storing temporary data for the test
884 * @param cfgfilename name of the configuration file to use;
885 * use NULL to only run with defaults
886 * @param tm main function of the testcase
887 * @param tm_cls closure for 'tm'
888 * @return 0 on success, 1 on error
891 GNUNET_TESTING_peer_run (const char *tmppath,
892 const char *cfgfilename,
893 GNUNET_TESTING_TestMain tm,
896 return GNUNET_TESTING_service_run (tmppath, "arm",
897 cfgfilename, tm, tm_cls);
902 * Structure for holding service data
904 struct ServiceContext
907 * The configuration of the peer in which the service is run
909 const struct GNUNET_CONFIGURATION_Handle *cfg;
912 * Callback to signal service startup
914 GNUNET_TESTING_TestMain tm;
917 * Closure for the above callback
924 * Callback to be called when SCHEDULER has been started
926 * @param cls the ServiceContext
927 * @param tc the TaskContext
930 service_run_main (void *cls,
931 const struct GNUNET_SCHEDULER_TaskContext *tc)
933 struct ServiceContext *sc = cls;
935 sc->tm (sc->tm_cls, sc->cfg);
940 * Start a single service (no ARM, except of course if the given
941 * service name is 'arm') and run a test using the testing library.
942 * Starts a service using the given configuration and then invokes the
943 * given callback. This function ALSO initializes the scheduler loop
944 * and should thus be called directly from "main". The testcase
945 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
947 * This function is useful if the testcase is for a single service
948 * and if that service doesn't itself depend on other services.
950 * @param tmppath path for storing temporary data for the test
951 * @param service_name name of the service to run
952 * @param cfgfilename name of the configuration file to use;
953 * use NULL to only run with defaults
954 * @param tm main function of the testcase
955 * @param tm_cls closure for 'tm'
956 * @return 0 on success, 1 on error
959 GNUNET_TESTING_service_run (const char *tmppath,
960 const char *service_name,
961 const char *cfgfilename,
962 GNUNET_TESTING_TestMain tm,
965 struct ServiceContext sc;
966 struct GNUNET_TESTING_System *system;
967 struct GNUNET_TESTING_Peer *peer;
968 struct GNUNET_CONFIGURATION_Handle *cfg;
970 system = GNUNET_TESTING_system_create (tmppath, "127.0.0.1");
973 cfg = GNUNET_CONFIGURATION_create ();
974 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
976 LOG (GNUNET_ERROR_TYPE_ERROR,
977 _("Failed to load configuration from %s\n"), cfgfilename);
978 GNUNET_CONFIGURATION_destroy (cfg);
979 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
982 peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
985 GNUNET_CONFIGURATION_destroy (cfg);
986 hostkeys_unload (system);
987 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
990 GNUNET_free (peer->main_binary);
991 GNUNET_asprintf (&peer->main_binary, "gnunet-service-%s", service_name);
992 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
994 GNUNET_TESTING_peer_destroy (peer);
995 GNUNET_CONFIGURATION_destroy (cfg);
996 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1002 GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1003 if (GNUNET_OK != GNUNET_TESTING_peer_stop (peer))
1005 GNUNET_TESTING_peer_destroy (peer);
1006 GNUNET_CONFIGURATION_destroy (cfg);
1007 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1010 GNUNET_TESTING_peer_destroy (peer);
1011 GNUNET_CONFIGURATION_destroy (cfg);
1012 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1017 /* end of testing.c */