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_new.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 * Bitmap where each TCP port that has already been reserved for
70 * some GNUnet peer is recorded. Note that we additionally need to
71 * test if a port is already in use by non-GNUnet components before
72 * assigning it to a peer/service. If we detect that a port is
73 * already in use, we also mark it in this bitmap. So all the bits
74 * that are zero merely indicate ports that MIGHT be available for
77 uint32_t reserved_tcp_ports[65536 / 32];
80 * Bitmap where each UDP port that has already been reserved for
81 * some GNUnet peer is recorded. Note that we additionally need to
82 * test if a port is already in use by non-GNUnet components before
83 * assigning it to a peer/service. If we detect that a port is
84 * already in use, we also mark it in this bitmap. So all the bits
85 * that are zero merely indicate ports that MIGHT be available for
88 uint32_t reserved_udp_ports[65536 / 32];
91 * Counter we use to make service home paths unique on this system;
92 * the full path consists of the tmppath and this number. Each
93 * UNIXPATH for a peer is also modified to include the respective
94 * path counter to ensure uniqueness. This field is incremented
95 * by one for each configured peer. Even if peers are destroyed,
96 * we never re-use path counters.
98 uint32_t path_counter;
101 * The number of hostkeys
103 uint32_t total_hostkeys;
108 * Handle for a GNUnet peer controlled by testing.
110 struct GNUNET_TESTING_Peer
114 * Path to the configuration file for this peer.
119 * Binary to be executed during 'GNUNET_TESTING_peer_start'.
120 * Typically 'gnunet-service-arm' (but can be set to a
121 * specific service by 'GNUNET_TESTING_service_run' if
127 * Handle to the running binary of the service, NULL if the
128 * peer/service is currently not running.
130 struct GNUNET_OS_Process *main_process;
135 * Lowest port used for GNUnet testing. Should be high enough to not
136 * conflict with other applications running on the hosts but be low
137 * enough to not conflict with client-ports (typically starting around
140 #define LOW_PORT 12000
144 * Highest port used for GNUnet testing. Should be low enough to not
145 * conflict with the port range for "local" ports (client apps; see
146 * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
148 #define HIGH_PORT 56000
152 * Testing includes a number of pre-created hostkeys for faster peer
153 * startup. This function loads such keys into memory from a file.
155 * @param system the testing system handle
156 * @return GNUNET_OK on success; GNUNET_SYSERR on error
159 hostkeys_load (struct GNUNET_TESTING_System *system)
161 struct GNUNET_DISK_FileHandle *fd;
166 data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
167 GNUNET_asprintf (&filename, "%s/testing_hostkeys.dat", data_dir);
168 GNUNET_free (data_dir);
170 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
172 LOG (GNUNET_ERROR_TYPE_ERROR,
173 _("Hostkeys file not found: %s\n"), filename);
174 GNUNET_free (filename);
175 return GNUNET_SYSERR;
177 /* Check hostkey file size, read entire thing into memory */
178 fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
179 GNUNET_DISK_PERM_NONE);
182 LOG (GNUNET_ERROR_TYPE_ERROR,
183 _("Could not open hostkeys file: %s\n"), filename);
184 GNUNET_free (filename);
185 return GNUNET_SYSERR;
188 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
192 GNUNET_DISK_file_close (fd);
193 GNUNET_free (filename);
194 return GNUNET_SYSERR; /* File is empty */
196 if (0 != (fs % HOSTKEYFILESIZE))
198 GNUNET_DISK_file_close (fd);
199 LOG (GNUNET_ERROR_TYPE_ERROR,
200 _("Incorrect hostkey file format: %s\n"), filename);
201 GNUNET_free (filename);
202 return GNUNET_SYSERR;
204 GNUNET_break (NULL == system->hostkeys_data);
205 system->total_hostkeys = fs / HOSTKEYFILESIZE;
206 /* FIXME: mmap instead? */
207 system->hostkeys_data = GNUNET_malloc_large (fs); /* free in hostkeys_unload */
208 GNUNET_assert (fs == GNUNET_DISK_file_read (fd, system->hostkeys_data, fs));
209 GNUNET_DISK_file_close (fd);
210 GNUNET_free (filename);
216 * Function to remove the loaded hostkeys
218 * @param system the testing system handle
221 hostkeys_unload (struct GNUNET_TESTING_System *system)
223 GNUNET_break (NULL != system->hostkeys_data);
224 GNUNET_free_non_null (system->hostkeys_data);
225 system->hostkeys_data = NULL;
226 system->total_hostkeys = 0;
231 * Create a system handle. There must only be one system
232 * handle per operating system.
234 * @param tmppath prefix path to use for all service homes
235 * @param controller hostname of the controlling host,
236 * service configurations are modified to allow
237 * control connections from this host; can be NULL
238 * @return handle to this system, NULL on error
240 struct GNUNET_TESTING_System *
241 GNUNET_TESTING_system_create (const char *tmppath,
242 const char *controller)
244 struct GNUNET_TESTING_System *system;
246 GNUNET_assert (NULL != tmppath);
247 system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
248 system->tmppath = GNUNET_strdup (tmppath);
249 if (NULL != controller)
250 system->controller = GNUNET_strdup (controller);
251 if (GNUNET_OK != hostkeys_load (system))
253 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
261 * Free system resources.
263 * @param system system to be freed
264 * @param remove_paths should the 'tmppath' and all subdirectories
265 * be removed (clean up on shutdown)?
268 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
271 if (NULL != system->hostkeys_data)
272 hostkeys_unload (system);
273 if (GNUNET_YES == remove_paths)
274 GNUNET_DISK_directory_remove (system->tmppath);
275 GNUNET_free (system->tmppath);
276 GNUNET_free_non_null (system->controller);
277 GNUNET_free (system);
282 * Reserve a TCP or UDP port for a peer.
284 * @param system system to use for reservation tracking
285 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
286 * @return 0 if no free port was available
289 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system,
292 struct GNUNET_NETWORK_Handle *socket;
293 struct addrinfo hint;
294 struct addrinfo *ret;
295 uint32_t *port_buckets;
304 FIXME: Instead of using getaddrinfo we should try to determine the port
305 status by the following heurestics.
307 On systems which support both IPv4 and IPv6, only ports open on both
308 address families are considered open.
309 On system with either IPv4 or IPv6. A port is considered open if it's
310 open in the respective address family
312 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
313 hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM;
314 hint.ai_protocol = 0;
317 hint.ai_canonname = NULL;
319 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
320 port_buckets = (GNUNET_YES == is_tcp) ?
321 system->reserved_tcp_ports : system->reserved_udp_ports;
322 for (index = (LOW_PORT / 32) + 1; index < (HIGH_PORT / 32); index++)
324 xor_image = (UINT32_MAX ^ port_buckets[index]);
325 if (0 == xor_image) /* Ports in the bucket are full */
330 if (0 == ((xor_image >> pos) & 1U))
335 open_port = (index * 32) + pos;
336 GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
338 GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
339 GNUNET_free (open_port_str);
340 socket = GNUNET_NETWORK_socket_create (ret->ai_family,
341 (GNUNET_YES == is_tcp) ?
342 SOCK_STREAM : SOCK_DGRAM,
344 GNUNET_assert (NULL != socket);
345 bind_status = GNUNET_NETWORK_socket_bind (socket,
349 GNUNET_NETWORK_socket_close (socket);
351 port_buckets[index] |= (1U << pos); /* Set the port bit */
352 if (GNUNET_OK == bind_status)
354 LOG (GNUNET_ERROR_TYPE_DEBUG,
355 "Found a free port %u\n", (unsigned int) open_port);
366 * Release reservation of a TCP or UDP port for a peer
367 * (used during GNUNET_TESTING_peer_destroy).
369 * @param system system to use for reservation tracking
370 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
371 * @param port reserved port to release
374 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
378 uint32_t *port_buckets;
382 port_buckets = (GNUNET_YES == is_tcp) ?
383 system->reserved_tcp_ports : system->reserved_udp_ports;
386 LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
387 if (0 == (port_buckets[bucket] & (1U << pos)))
389 GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
392 port_buckets[bucket] &= ~(1U << pos);
397 * Reserve a SERVICEHOME path for a peer.
399 * @param system system to use for reservation tracking
400 * @return NULL on error, otherwise fresh unique path to use
401 * as the servicehome for the peer; must be freed by the caller
405 reserve_path (struct GNUNET_TESTING_System *system)
409 GNUNET_asprintf (&reserved_path,
410 "%s/%u", system->tmppath, system->path_counter++);
411 return reserved_path;
416 * Testing includes a number of pre-created hostkeys for
417 * faster peer startup. This function can be used to
418 * access the n-th key of those pre-created hostkeys; note
419 * that these keys are ONLY useful for testing and not
420 * secure as the private keys are part of the public
421 * GNUnet source code.
423 * This is primarily a helper function used internally
424 * by 'GNUNET_TESTING_peer_configure'.
426 * @param system the testing system handle
427 * @param key_number desired pre-created hostkey to obtain
428 * @param id set to the peer's identity (hash of the public
429 * key; if NULL, GNUNET_SYSERR is returned immediately
430 * @return GNUNET_SYSERR on error (not enough keys)
433 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
435 struct GNUNET_PeerIdentity *id)
437 struct GNUNET_CRYPTO_RsaPrivateKey *private_key;
438 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
440 if ((NULL == id) || (NULL == system->hostkeys_data))
441 return GNUNET_SYSERR;
442 if (key_number >= system->total_hostkeys)
444 LOG (GNUNET_ERROR_TYPE_ERROR,
445 _("Key number %u does not exist\n"), key_number);
446 return GNUNET_SYSERR;
448 private_key = GNUNET_CRYPTO_rsa_decode_key (system->hostkeys_data +
449 (key_number * HOSTKEYFILESIZE),
451 if (NULL == private_key)
453 LOG (GNUNET_ERROR_TYPE_ERROR,
454 _("Error while decoding key %u\n"), key_number);
455 return GNUNET_SYSERR;
457 GNUNET_CRYPTO_rsa_key_get_public (private_key, &public_key);
458 GNUNET_CRYPTO_hash (&public_key,
459 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
461 GNUNET_CRYPTO_rsa_key_free (private_key);
467 * Structure for holding data to build new configurations from a configuration
473 * The system for which we are building configurations
475 struct GNUNET_TESTING_System *system;
478 * The configuration we are building
480 struct GNUNET_CONFIGURATION_Handle *cfg;
483 * The customized service home path for this peer
488 * build status - to signal error while building a configuration
495 * Function to iterate over options. Copies
496 * the options to the target configuration,
497 * updating PORT values as needed.
499 * @param cls the UpdateContext
500 * @param section name of the section
501 * @param option name of the option
502 * @param value value of the option
505 update_config (void *cls, const char *section, const char *option,
508 struct UpdateContext *uc = cls;
512 char *single_variable;
513 char *per_host_variable;
514 unsigned long long num_per_host;
517 if (GNUNET_OK != uc->status)
519 if (! ((0 == strcmp (option, "PORT"))
520 || (0 == strcmp (option, "UNIXPATH"))
521 || (0 == strcmp (option, "HOSTNAME"))))
523 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
524 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
525 if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
529 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
532 /* FIXME: What about UDP? */
533 new_port = GNUNET_TESTING_reserve_port (uc->system, GNUNET_YES);
536 uc->status = GNUNET_SYSERR;
539 GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
542 else if ((ival != 0) &&
544 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
546 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
550 /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
551 /* ival + ctx->fdnum % num_per_host); */
553 GNUNET_break (0); /* FIXME */
556 if (0 == strcmp (option, "UNIXPATH"))
559 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
562 GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock",
563 uc->service_home, section);
566 else if ((GNUNET_YES ==
567 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
572 GNUNET_break(0); /* FIXME */
575 if ((0 == strcmp (option, "HOSTNAME")) && (NULL != uc->system->controller))
577 value = uc->system->controller;
579 GNUNET_free (single_variable);
580 GNUNET_free (per_host_variable);
581 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
586 * Section iterator to set ACCEPT_FROM in all sections
588 * @param cls the UpdateContext
589 * @param section name of the section
592 update_config_sections (void *cls,
595 struct UpdateContext *uc = cls;
596 char *orig_allowed_hosts;
600 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "ACCEPT_FROM",
601 &orig_allowed_hosts))
603 orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
605 if (NULL == uc->system->controller)
606 allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
608 GNUNET_asprintf (&allowed_hosts, "%s%s;", orig_allowed_hosts,
609 uc->system->controller);
610 GNUNET_free (orig_allowed_hosts);
611 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, "ACCEPT_FROM",
613 GNUNET_free (allowed_hosts);
618 * Create a new configuration using the given configuration
619 * as a template; ports and paths will be modified to select
620 * available ports on the local system. If we run
621 * out of "*port" numbers, return SYSERR.
623 * This is primarily a helper function used internally
624 * by 'GNUNET_TESTING_peer_configure'.
626 * @param system system to use to coordinate resource usage
627 * @param cfg template configuration to update
628 * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
629 * be incomplete and should not be used there upon
632 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
633 struct GNUNET_CONFIGURATION_Handle *cfg)
635 struct UpdateContext uc;
636 char *default_config;
640 uc.status = GNUNET_OK;
641 GNUNET_asprintf (&uc.service_home, "%s/%u", system->tmppath,
642 system->path_counter++);
643 GNUNET_asprintf (&default_config, "%s/config", uc.service_home);
644 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
646 GNUNET_free (default_config);
647 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME",
649 /* make PORTs and UNIXPATHs unique */
650 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
651 /* allow connections to services from system controller host */
652 GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
653 /* enable loopback-based connections between peers */
654 GNUNET_CONFIGURATION_set_value_string (cfg,
656 "USE_LOCALADDR", "YES");
657 GNUNET_free (uc.service_home);
663 * Configure a GNUnet peer. GNUnet must be installed on the local
664 * system and available in the PATH.
666 * @param system system to use to coordinate resource usage
667 * @param cfg configuration to use; will be UPDATED (to reflect needed
668 * changes in port numbers and paths)
669 * @param key_number number of the hostkey to use for the peer
670 * @param id identifier for the daemon, will be set, can be NULL
671 * @param emsg set to error message (set to NULL on success), can be NULL
672 * @return handle to the peer, NULL on error
674 struct GNUNET_TESTING_Peer *
675 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
676 struct GNUNET_CONFIGURATION_Handle *cfg,
678 struct GNUNET_PeerIdentity *id,
681 struct GNUNET_TESTING_Peer *peer;
682 struct GNUNET_DISK_FileHandle *fd;
684 char hostkey_filename[128];
685 char *config_filename;
690 if (GNUNET_OK != GNUNET_TESTING_configuration_create (system, cfg))
692 GNUNET_asprintf (&emsg_,
693 _("Failed to create configuration for peer (not enough free ports?)\n"));
694 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
701 if (key_number >= system->total_hostkeys)
703 GNUNET_asprintf (&emsg_,
704 _("You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"),
705 (unsigned int) system->total_hostkeys);
706 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
714 (GNUNET_SYSERR == GNUNET_TESTING_hostkey_get (system, key_number, id)))
716 GNUNET_asprintf (&emsg_,
717 _("Failed to initialize hostkey for peer %u\n"),
718 (unsigned int) key_number);
719 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
726 GNUNET_assert (GNUNET_OK ==
727 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
730 GNUNET_snprintf (hostkey_filename, sizeof (hostkey_filename), "%s/.hostkey",
732 GNUNET_free (service_home);
733 fd = GNUNET_DISK_file_open (hostkey_filename,
734 GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
735 GNUNET_DISK_PERM_USER_READ
736 | GNUNET_DISK_PERM_USER_WRITE);
742 if (HOSTKEYFILESIZE !=
743 GNUNET_DISK_file_write (fd, system->hostkeys_data
744 + (key_number * HOSTKEYFILESIZE),
747 GNUNET_asprintf (&emsg_,
748 _("Failed to write hostkey file for peer %u: %s\n"),
749 (unsigned int) key_number,
751 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
756 GNUNET_DISK_file_close (fd);
759 GNUNET_DISK_file_close (fd);
760 GNUNET_assert (GNUNET_OK ==
761 GNUNET_CONFIGURATION_get_value_string
762 (cfg, "PATHS", "DEFAULTCONFIG", &config_filename));
763 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
765 GNUNET_asprintf (&emsg_,
766 _("Failed to write configuration file `%s' for peer %u: %s\n"),
768 (unsigned int) key_number,
770 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
775 GNUNET_free (config_filename);
778 peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
779 peer->cfgfile = config_filename; /* Free in peer_destroy */
780 peer->main_binary = GNUNET_strdup ("gnunet-service-arm");
788 * @param peer peer to start
789 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
792 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
794 if (NULL != peer->main_process)
797 return GNUNET_SYSERR;
799 GNUNET_assert (NULL != peer->cfgfile);
800 peer->main_process = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL,
806 if (NULL == peer->main_process)
808 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
809 _("Failed to start `%s': %s\n"),
812 return GNUNET_SYSERR;
821 * @param peer peer to stop
822 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer not running)
825 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
827 if (NULL == peer->main_process)
830 return GNUNET_SYSERR;
832 (void) GNUNET_OS_process_kill (peer->main_process, SIGTERM);
833 GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (peer->main_process));
834 GNUNET_OS_process_destroy (peer->main_process);
835 peer->main_process = NULL;
841 * Destroy the peer. Releases resources locked during peer configuration.
842 * If the peer is still running, it will be stopped AND a warning will be
843 * printed (users of the API should stop the peer explicitly first).
845 * @param peer peer to destroy
848 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
850 if (NULL != peer->main_process)
853 GNUNET_TESTING_peer_stop (peer);
855 GNUNET_free (peer->cfgfile);
856 GNUNET_free (peer->main_binary);
862 * Start a single peer and run a test using the testing library.
863 * Starts a peer using the given configuration and then invokes the
864 * given callback. This function ALSO initializes the scheduler loop
865 * and should thus be called directly from "main". The testcase
866 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
868 * @param tmppath path for storing temporary data for the test
869 * @param cfgfilename name of the configuration file to use;
870 * use NULL to only run with defaults
871 * @param tm main function of the testcase
872 * @param tm_cls closure for 'tm'
873 * @return 0 on success, 1 on error
876 GNUNET_TESTING_peer_run (const char *tmppath,
877 const char *cfgfilename,
878 GNUNET_TESTING_TestMain tm,
881 return GNUNET_TESTING_service_run (tmppath, "arm",
882 cfgfilename, tm, tm_cls);
887 * Structure for holding service data
889 struct ServiceContext
892 * The configuration of the peer in which the service is run
894 const struct GNUNET_CONFIGURATION_Handle *cfg;
897 * Callback to signal service startup
899 GNUNET_TESTING_TestMain tm;
902 * Closure for the above callback
909 * Callback to be called when SCHEDULER has been started
911 * @param cls the ServiceContext
912 * @param tc the TaskContext
915 service_run_main (void *cls,
916 const struct GNUNET_SCHEDULER_TaskContext *tc)
918 struct ServiceContext *sc = cls;
920 sc->tm (sc->tm_cls, sc->cfg);
925 * Start a single service (no ARM, except of course if the given
926 * service name is 'arm') and run a test using the testing library.
927 * Starts a service using the given configuration and then invokes the
928 * given callback. This function ALSO initializes the scheduler loop
929 * and should thus be called directly from "main". The testcase
930 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
932 * This function is useful if the testcase is for a single service
933 * and if that service doesn't itself depend on other services.
935 * @param tmppath path for storing temporary data for the test
936 * @param service_name name of the service to run
937 * @param cfgfilename name of the configuration file to use;
938 * use NULL to only run with defaults
939 * @param tm main function of the testcase
940 * @param tm_cls closure for 'tm'
941 * @return 0 on success, 1 on error
944 GNUNET_TESTING_service_run (const char *tmppath,
945 const char *service_name,
946 const char *cfgfilename,
947 GNUNET_TESTING_TestMain tm,
950 struct ServiceContext sc;
951 struct GNUNET_TESTING_System *system;
952 struct GNUNET_TESTING_Peer *peer;
953 struct GNUNET_CONFIGURATION_Handle *cfg;
955 system = GNUNET_TESTING_system_create (tmppath, "127.0.0.1");
958 cfg = GNUNET_CONFIGURATION_create ();
959 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
961 LOG (GNUNET_ERROR_TYPE_ERROR,
962 _("Failed to load configuration from %s\n"), cfgfilename);
963 GNUNET_CONFIGURATION_destroy (cfg);
964 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
967 peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
970 GNUNET_CONFIGURATION_destroy (cfg);
971 hostkeys_unload (system);
972 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
975 GNUNET_free (peer->main_binary);
976 GNUNET_asprintf (&peer->main_binary, "gnunet-service-%s", service_name);
977 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
979 GNUNET_TESTING_peer_destroy (peer);
980 GNUNET_CONFIGURATION_destroy (cfg);
981 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
987 GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
988 if (GNUNET_OK != GNUNET_TESTING_peer_stop (peer))
990 GNUNET_TESTING_peer_destroy (peer);
991 GNUNET_CONFIGURATION_destroy (cfg);
992 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
995 GNUNET_TESTING_peer_destroy (peer);
996 GNUNET_CONFIGURATION_destroy (cfg);
997 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1002 /* end of testing_new.c */