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__)
39 #define TIME_REL_SEC(sec) \
40 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
44 * Size of a hostkey when written to a file
46 #define HOSTKEYFILESIZE 914
50 * Handle for a system on which GNUnet peers are executed;
51 * a system is used for reserving unique paths and ports.
53 struct GNUNET_TESTING_System
56 * Prefix (i.e. "/tmp/gnunet-testing/") we prepend to each
62 * The hostname of the controller
67 * Hostkeys data, contains "HOSTKEYFILESIZE * total_hostkeys" bytes.
72 * Bitmap where each TCP port that has already been reserved for
73 * some GNUnet peer is recorded. Note that we additionally need to
74 * test if a port is already in use by non-GNUnet components before
75 * assigning it to a peer/service. If we detect that a port is
76 * already in use, we also mark it in this bitmap. So all the bits
77 * that are zero merely indicate ports that MIGHT be available for
80 uint32_t reserved_tcp_ports[65536 / 32];
83 * Bitmap where each UDP port that has already been reserved for
84 * some GNUnet peer is recorded. Note that we additionally need to
85 * test if a port is already in use by non-GNUnet components before
86 * assigning it to a peer/service. If we detect that a port is
87 * already in use, we also mark it in this bitmap. So all the bits
88 * that are zero merely indicate ports that MIGHT be available for
91 uint32_t reserved_udp_ports[65536 / 32];
94 * Counter we use to make service home paths unique on this system;
95 * the full path consists of the tmppath and this number. Each
96 * UNIXPATH for a peer is also modified to include the respective
97 * path counter to ensure uniqueness. This field is incremented
98 * by one for each configured peer. Even if peers are destroyed,
99 * we never re-use path counters.
101 uint32_t path_counter;
104 * The number of hostkeys
106 uint32_t total_hostkeys;
111 * Handle for a GNUnet peer controlled by testing.
113 struct GNUNET_TESTING_Peer
117 * Path to the configuration file for this peer.
122 * Binary to be executed during 'GNUNET_TESTING_peer_start'.
123 * Typically 'gnunet-service-arm' (but can be set to a
124 * specific service by 'GNUNET_TESTING_service_run' if
130 * Handle to the running binary of the service, NULL if the
131 * peer/service is currently not running.
133 struct GNUNET_OS_Process *main_process;
138 * Lowest port used for GNUnet testing. Should be high enough to not
139 * conflict with other applications running on the hosts but be low
140 * enough to not conflict with client-ports (typically starting around
143 #define LOW_PORT 12000
147 * Highest port used for GNUnet testing. Should be low enough to not
148 * conflict with the port range for "local" ports (client apps; see
149 * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
151 #define HIGH_PORT 56000
155 * Create a system handle. There must only be one system
156 * handle per operating system.
158 * @param tmppath prefix path to use for all service homes
159 * @param controller hostname of the controlling host,
160 * service configurations are modified to allow
161 * control connections from this host; can be NULL
162 * @return handle to this system, NULL on error
164 struct GNUNET_TESTING_System *
165 GNUNET_TESTING_system_create (const char *tmppath,
166 const char *controller)
168 struct GNUNET_TESTING_System *system;
172 system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
173 system->tmppath = GNUNET_strdup (tmppath);
174 if (NULL != controller)
175 system->controller = GNUNET_strdup (controller);
181 * Free system resources.
183 * @param system system to be freed
184 * @param remove_paths should the 'tmppath' and all subdirectories
185 * be removed (clean up on shutdown)?
188 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
191 if (NULL != system->hostkeys_data)
193 GNUNET_break (0); /* Use GNUNET_TESTING_hostkeys_unload() */
194 GNUNET_free (system->hostkeys_data);
195 system->hostkeys_data = NULL;
196 system->total_hostkeys = 0;
198 if (GNUNET_YES == remove_paths)
199 GNUNET_DISK_directory_remove (system->tmppath);
200 GNUNET_free (system->tmppath);
201 GNUNET_free_non_null (system->controller);
202 GNUNET_free (system);
207 * Reserve a TCP or UDP port for a peer.
209 * @param system system to use for reservation tracking
210 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
211 * @return 0 if no free port was available
214 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system,
217 struct GNUNET_NETWORK_Handle *socket;
218 struct addrinfo hint;
219 struct addrinfo *ret;
220 uint32_t *port_buckets;
228 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
229 hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM;
230 hint.ai_protocol = 0;
233 hint.ai_canonname = NULL;
235 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
236 port_buckets = (GNUNET_YES == is_tcp) ?
237 system->reserved_tcp_ports : system->reserved_udp_ports;
238 for (index = (LOW_PORT / 32) + 1; index < (HIGH_PORT / 32); index++)
240 xor_image = (UINT32_MAX ^ port_buckets[index]);
241 if (0 == xor_image) /* Ports in the bucket are full */
246 if (0 == ((xor_image >> pos) & 1U))
251 open_port = (index * 32) + pos;
252 GNUNET_asprintf (&open_port_str, "%u", open_port);
254 GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
255 GNUNET_free (open_port_str);
256 socket = GNUNET_NETWORK_socket_create (ret->ai_family,
257 (GNUNET_YES == is_tcp) ?
258 SOCK_STREAM : SOCK_DGRAM,
260 GNUNET_assert (NULL != socket);
261 bind_status = GNUNET_NETWORK_socket_bind (socket,
265 GNUNET_NETWORK_socket_close (socket);
267 port_buckets[index] |= (1U << pos); /* Set the port bit */
268 if (GNUNET_OK == bind_status)
278 * Release reservation of a TCP or UDP port for a peer
279 * (used during GNUNET_TESTING_peer_destroy).
281 * @param system system to use for reservation tracking
282 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
283 * @param port reserved port to release
286 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
290 uint32_t *port_buckets;
294 port_buckets = (GNUNET_YES == is_tcp) ?
295 system->reserved_tcp_ports : system->reserved_udp_ports;
298 LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
299 if (0 == (port_buckets[bucket] & (1U << pos)))
301 GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
304 port_buckets[bucket] &= ~(1U << pos);
309 * Reserve a SERVICEHOME path for a peer.
311 * @param system system to use for reservation tracking
312 * @return NULL on error, otherwise fresh unique path to use
313 * as the servicehome for the peer; must be freed by the caller
317 reserve_path (struct GNUNET_TESTING_System *system)
321 GNUNET_asprintf (&reserved_path,
322 "%s/%u", system->tmppath, system->path_counter++);
323 return reserved_path;
328 * Testing includes a number of pre-created hostkeys for faster peer
329 * startup. This function loads such keys into memory from a file.
331 * @param system the testing system handle
332 * @param filename the path of the hostkeys file
333 * @return GNUNET_OK on success; GNUNET_SYSERR on error
336 GNUNET_TESTING_hostkeys_load (struct GNUNET_TESTING_System *system,
337 const char *filename)
339 struct GNUNET_DISK_FileHandle *fd;
342 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
344 LOG (GNUNET_ERROR_TYPE_ERROR,
345 "Hostkeys file not found: %s\n", filename);
346 return GNUNET_SYSERR;
348 /* Check hostkey file size, read entire thing into memory */
349 fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
350 GNUNET_DISK_PERM_NONE);
353 LOG (GNUNET_ERROR_TYPE_ERROR,
354 "Could not open hostkeys file: %s\n", filename);
355 return GNUNET_SYSERR;
358 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
362 GNUNET_DISK_file_close (fd);
363 return GNUNET_SYSERR; /* File is empty */
365 if (0 != (fs % HOSTKEYFILESIZE))
367 GNUNET_DISK_file_close (fd);
368 LOG (GNUNET_ERROR_TYPE_ERROR,
369 "Incorrect hostkey file format: %s\n", filename);
370 return GNUNET_SYSERR;
372 GNUNET_break (NULL == system->hostkeys_data);
373 system->total_hostkeys = fs / HOSTKEYFILESIZE;
374 system->hostkeys_data = GNUNET_malloc_large (fs); /* free in hostkeys_unload */
375 GNUNET_assert (fs == GNUNET_DISK_file_read (fd, system->hostkeys_data, fs));
376 GNUNET_DISK_file_close (fd);
382 * Function to remove the loaded hostkeys
384 * @param system the testing system handle
387 GNUNET_TESTING_hostkeys_unload (struct GNUNET_TESTING_System *system)
389 GNUNET_break (NULL != system->hostkeys_data);
390 GNUNET_free_non_null (system->hostkeys_data);
391 system->hostkeys_data = NULL;
392 system->total_hostkeys = 0;
397 * Testing includes a number of pre-created hostkeys for
398 * faster peer startup. This function can be used to
399 * access the n-th key of those pre-created hostkeys; note
400 * that these keys are ONLY useful for testing and not
401 * secure as the private keys are part of the public
402 * GNUnet source code.
404 * This is primarily a helper function used internally
405 * by 'GNUNET_TESTING_peer_configure'.
407 * @param system the testing system handle
408 * @param key_number desired pre-created hostkey to obtain
409 * @param id set to the peer's identity (hash of the public
410 * key; if NULL, GNUNET_SYSERR is returned immediately
411 * @return GNUNET_SYSERR on error (not enough keys)
414 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
416 struct GNUNET_PeerIdentity *id)
418 struct GNUNET_CRYPTO_RsaPrivateKey *private_key;
419 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
421 if ((NULL == id) || (NULL == system->hostkeys_data))
422 return GNUNET_SYSERR;
423 if (key_number >= system->total_hostkeys)
425 LOG (GNUNET_ERROR_TYPE_ERROR,
426 _("Key number %u does not exist\n"), key_number);
427 return GNUNET_SYSERR;
429 private_key = GNUNET_CRYPTO_rsa_decode_key (system->hostkeys_data +
430 (key_number * HOSTKEYFILESIZE),
432 if (NULL == private_key)
434 LOG (GNUNET_ERROR_TYPE_ERROR,
435 _("Error while decoding key %u\n"), key_number);
436 return GNUNET_SYSERR;
438 GNUNET_CRYPTO_rsa_key_get_public (private_key, &public_key);
439 GNUNET_CRYPTO_hash (&public_key,
440 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
442 GNUNET_CRYPTO_rsa_key_free (private_key);
448 * Structure for holding data to build new configurations from a configuration
454 * The system for which we are building configurations
456 struct GNUNET_TESTING_System *system;
459 * The configuration we are building
461 struct GNUNET_CONFIGURATION_Handle *cfg;
464 * The customized service home path for this peer
469 * build status - to signal error while building a configuration
476 * Function to iterate over options. Copies
477 * the options to the target configuration,
478 * updating PORT values as needed.
480 * @param cls the UpdateContext
481 * @param section name of the section
482 * @param option name of the option
483 * @param value value of the option
486 update_config (void *cls, const char *section, const char *option,
489 struct UpdateContext *uc = cls;
493 char *single_variable;
494 char *per_host_variable;
495 unsigned long long num_per_host;
498 if (GNUNET_OK != uc->status)
500 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
501 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
502 if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
506 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
509 /* FIXME: What about UDP? */
510 new_port = GNUNET_TESTING_reserve_port (uc->system, GNUNET_YES);
513 uc->status = GNUNET_SYSERR;
516 GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
519 else if ((ival != 0) &&
521 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
523 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
527 /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
528 /* ival + ctx->fdnum % num_per_host); */
530 GNUNET_break (0); /* FIXME */
533 if (0 == strcmp (option, "UNIXPATH"))
536 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
539 GNUNET_snprintf (uval, sizeof (uval), "%s\\%s.sock",
540 uc->service_home, section);
543 else if ((GNUNET_YES ==
544 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
549 GNUNET_break(0); /* FIXME */
552 if ((0 == strcmp (option, "HOSTNAME")) && (NULL != uc->system->controller))
554 value = uc->system->controller;
556 GNUNET_free (single_variable);
557 GNUNET_free (per_host_variable);
558 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
563 * Section iterator to set ACCEPT_FROM in all sections
565 * @param cls the UpdateContext
566 * @param section name of the section
569 update_config_sections (void *cls,
572 struct UpdateContext *uc = cls;
573 char *orig_allowed_hosts;
577 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "ACCEPT_FROM",
578 &orig_allowed_hosts))
580 orig_allowed_hosts = "127.0.0.1;";
582 if (NULL == uc->system->controller)
583 allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
585 GNUNET_asprintf (&allowed_hosts, "%s %s;", orig_allowed_hosts,
586 uc->system->controller);
587 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, "ACCEPT_FROM",
589 GNUNET_free (allowed_hosts);
594 * Create a new configuration using the given configuration
595 * as a template; ports and paths will be modified to select
596 * available ports on the local system. If we run
597 * out of "*port" numbers, return SYSERR.
599 * This is primarily a helper function used internally
600 * by 'GNUNET_TESTING_peer_configure'.
602 * @param system system to use to coordinate resource usage
603 * @param cfg template configuration to update
604 * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
605 * be incomplete and should not be used there upon
608 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
609 struct GNUNET_CONFIGURATION_Handle *cfg)
611 struct UpdateContext uc;
615 uc.status = GNUNET_OK;
616 GNUNET_asprintf (&uc.service_home, "%s\\%u", system->tmppath,
617 system->path_counter++);
618 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME",
620 /* make PORTs and UNIXPATHs unique */
621 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
622 /* allow connections to services from system controller host */
623 GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
624 /* enable loopback-based connections between peers */
625 GNUNET_CONFIGURATION_set_value_string (cfg,
627 "USE_LOCALADDR", "YES");
628 GNUNET_free (uc.service_home);
634 * Configure a GNUnet peer. GNUnet must be installed on the local
635 * system and available in the PATH.
637 * @param system system to use to coordinate resource usage
638 * @param cfg configuration to use; will be UPDATED (to reflect needed
639 * changes in port numbers and paths)
640 * @param key_number number of the hostkey to use for the peer
641 * @param id identifier for the daemon, will be set, can be NULL
642 * @param emsg set to error message (set to NULL on success), can be NULL
643 * @return handle to the peer, NULL on error
645 struct GNUNET_TESTING_Peer *
646 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
647 struct GNUNET_CONFIGURATION_Handle *cfg,
649 struct GNUNET_PeerIdentity *id,
652 struct GNUNET_TESTING_Peer *peer;
653 struct GNUNET_DISK_FileHandle *fd;
655 char hostkey_filename[128];
656 char *config_filename;
658 if (GNUNET_OK != GNUNET_TESTING_configuration_create (system, cfg))
660 GNUNET_asprintf (emsg,
661 _("Failed to create configuration for peer (not enough free ports?)\n"));
662 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
666 if (key_number >= system->total_hostkeys)
668 GNUNET_asprintf (emsg,
669 _("You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"),
670 (unsigned int) system->total_hostkeys);
671 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
676 (GNUNET_SYSERR == GNUNET_TESTING_hostkey_get (system, key_number, id)))
678 GNUNET_asprintf (emsg,
679 _("Failed to initialize hostkey for peer %u\n"),
680 (unsigned int) key_number);
681 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
685 GNUNET_assert (GNUNET_OK ==
686 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
689 GNUNET_snprintf (hostkey_filename, sizeof (hostkey_filename), "%s\\.hostkey",
691 fd = GNUNET_DISK_file_open (hostkey_filename,
692 GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
693 GNUNET_DISK_PERM_USER_READ
694 | GNUNET_DISK_PERM_USER_WRITE);
700 if (HOSTKEYFILESIZE !=
701 GNUNET_DISK_file_write (fd, system->hostkeys_data
702 + (key_number * HOSTKEYFILESIZE),
705 GNUNET_asprintf (emsg,
706 _("Failed to write hostkey file for peer %u: %s\n"),
707 (unsigned int) key_number,
709 GNUNET_DISK_file_close (fd);
712 GNUNET_DISK_file_close (fd);
713 GNUNET_asprintf (&config_filename, "%s\\config", service_home);
714 GNUNET_free (service_home);
715 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
717 GNUNET_asprintf (emsg,
718 _("Failed to write configuration file `%s' for peer %u: %s\n"),
720 (unsigned int) key_number,
724 peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
725 peer->cfgfile = config_filename; /* Free in peer_destroy */
726 peer->main_binary = GNUNET_strdup ("gnunet-service-arm");
734 * @param peer peer to start
735 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
738 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
740 if (NULL != peer->main_process)
743 return GNUNET_SYSERR;
745 GNUNET_assert (NULL != peer->cfgfile);
746 peer->main_process = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL,
747 peer->main_binary, "-c",
750 if (NULL == peer->main_process)
752 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
753 _("Failed to start `%s': %s\n"),
756 return GNUNET_SYSERR;
765 * @param peer peer to stop
766 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer not running)
769 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
771 if (NULL == peer->main_process)
774 return GNUNET_SYSERR;
776 (void) GNUNET_OS_process_kill (peer->main_process, SIGTERM);
777 GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (peer->main_process));
778 GNUNET_OS_process_destroy (peer->main_process);
779 peer->main_process = NULL;
785 * Destroy the peer. Releases resources locked during peer configuration.
786 * If the peer is still running, it will be stopped AND a warning will be
787 * printed (users of the API should stop the peer explicitly first).
789 * @param peer peer to destroy
792 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
794 if (NULL != peer->main_process)
797 GNUNET_TESTING_peer_stop (peer);
799 GNUNET_free (peer->cfgfile);
800 GNUNET_free (peer->main_binary);
806 * Start a single peer and run a test using the testing library.
807 * Starts a peer using the given configuration and then invokes the
808 * given callback. This function ALSO initializes the scheduler loop
809 * and should thus be called directly from "main". The testcase
810 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
812 * @param tmppath path for storing temporary data for the test
813 * @param cfgfilename name of the configuration file to use;
814 * use NULL to only run with defaults
815 * @param tm main function of the testcase
816 * @param tm_cls closure for 'tm'
817 * @return 0 on success, 1 on error
820 GNUNET_TESTING_peer_run (const char *tmppath,
821 const char *cfgfilename,
822 GNUNET_TESTING_TestMain tm,
825 return GNUNET_TESTING_service_run (tmppath, "arm",
826 cfgfilename, tm, tm_cls);
831 * Structure for holding service data
833 struct ServiceContext
836 * The service's main process
838 struct GNUNET_OS_Process *main_process;
841 * Callback to signal service startup
843 GNUNET_TESTING_TestMain tm;
846 * Closure for the above callback
853 * Scheduler callback to stop service upon call to GNUNET_SCHEDULER_shutdown
855 * @param cls the ServiceContext
856 * @param tc the TaskContext
859 stop_service (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
866 * Scheduler callback to stop service upon call to GNUNET_SCHEDULER_shutdown
868 * @param cls the ServiceContext
869 * @param tc the TaskContext
872 check_service_status (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
879 service_run_main (void *cls,
880 const struct GNUNET_SCHEDULER_TaskContext *tc)
882 struct ServiceContext *sc = cls;
884 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
886 GNUNET_SCHEDULER_add_delayed (TIME_REL_SEC(3), &check_service_status, sc);
893 * Start a single service (no ARM, except of course if the given
894 * service name is 'arm') and run a test using the testing library.
895 * Starts a service using the given configuration and then invokes the
896 * given callback. This function ALSO initializes the scheduler loop
897 * and should thus be called directly from "main". The testcase
898 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
900 * This function is useful if the testcase is for a single service
901 * and if that service doesn't itself depend on other services.
903 * @param tmppath path for storing temporary data for the test
904 * @param service_name name of the service to run
905 * @param cfgfilename name of the configuration file to use;
906 * use NULL to only run with defaults
907 * @param tm main function of the testcase
908 * @param tm_cls closure for 'tm'
909 * @return 0 on success, 1 on error
912 GNUNET_TESTING_service_run (const char *tmppath,
913 const char *service_name,
914 const char *cfgfilename,
915 GNUNET_TESTING_TestMain tm,
918 struct ServiceContext *sc;
921 GNUNET_assert (NULL != service_name);
922 GNUNET_snprintf (uval, sizeof (uval), "gnunet-service-%s", service_name);
923 sc = GNUNET_malloc (sizeof (struct ServiceContext));
925 // FIXME: GNUNET_TESTING_peer_start...
926 if (NULL == cfgfilename)
927 sc->main_process = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, uval, NULL);
929 sc->main_process = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, uval,
930 "-c", cfgfilename, NULL);
931 if (NULL == sc->main_process)
933 LOG (GNUNET_ERROR_TYPE_ERROR, "Failed to start process %s\n", service_name);
939 GNUNET_SCHEDULER_run (&service_run_main, sc);
940 // FIXME: GNUNET_TESTING_peer_stop...
946 /* end of testing_new.c */