2 This file is part of GNUnet
3 Copyright (C) 2008, 2009, 2012 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
17 * @file testing/testing.c
18 * @brief convenience API for writing testcases for GNUnet
19 * Many testcases need to start and stop a peer/service
20 * and this library is supposed to make that easier
21 * for TESTCASES. Normal programs should always
22 * use functions from gnunet_{util,arm}_lib.h. This API is
23 * ONLY for writing testcases (or internal use of the testbed).
24 * @author Christian Grothoff
28 #include "gnunet_util_lib.h"
29 #include "gnunet_arm_service.h"
30 #include "gnunet_testing_lib.h"
32 #define LOG(kind,...) \
33 GNUNET_log_from (kind, "testing-api", __VA_ARGS__)
37 * We need pipe control only on WINDOWS
40 #define PIPE_CONTROL GNUNET_YES
42 #define PIPE_CONTROL GNUNET_NO
47 * Lowest port used for GNUnet testing. Should be high enough to not
48 * conflict with other applications running on the hosts but be low
49 * enough to not conflict with client-ports (typically starting around
52 #define LOW_PORT 12000
55 * Highest port used for GNUnet testing. Should be low enough to not
56 * conflict with the port range for "local" ports (client apps; see
57 * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
59 #define HIGH_PORT 56000
62 struct SharedServiceInstance
64 struct SharedService *ss;
68 struct GNUNET_OS_Process *proc;
81 struct SharedServiceInstance **instances;
83 struct GNUNET_CONFIGURATION_Handle *cfg;
89 unsigned int n_instances;
94 * Handle for a system on which GNUnet peers are executed;
95 * a system is used for reserving unique paths and ports.
97 struct GNUNET_TESTING_System
100 * Prefix (i.e. "/tmp/gnunet-testing/") we prepend to each
106 * The trusted ip. Can either be a single ip address or a network address in
117 * Hostkeys data, contains "GNUNET_TESTING_HOSTKEYFILESIZE * total_hostkeys" bytes.
122 * memory map for @e hostkeys_data.
124 struct GNUNET_DISK_MapHandle *map;
126 struct SharedService **shared_services;
128 unsigned int n_shared_services;
131 * Bitmap where each port that has already been reserved for some GNUnet peer
132 * is recorded. Note that we make no distinction between TCP and UDP ports
133 * and test if a port is already in use before assigning it to a peer/service.
134 * If we detect that a port is already in use, we also mark it in this bitmap.
135 * So all the bits that are zero merely indicate ports that MIGHT be available
138 uint32_t reserved_ports[65536 / 32];
141 * Counter we use to make service home paths unique on this system;
142 * the full path consists of the tmppath and this number. Each
143 * UNIXPATH for a peer is also modified to include the respective
144 * path counter to ensure uniqueness. This field is incremented
145 * by one for each configured peer. Even if peers are destroyed,
146 * we never re-use path counters.
148 uint32_t path_counter;
151 * The number of hostkeys
153 uint32_t total_hostkeys;
156 * Lowest port we are allowed to use.
161 * Highest port we are allowed to use.
168 * Handle for a GNUnet peer controlled by testing.
170 struct GNUNET_TESTING_Peer
173 * The TESTING system associated with this peer
175 struct GNUNET_TESTING_System *system;
178 * Path to the configuration file for this peer.
183 * Binary to be executed during 'GNUNET_TESTING_peer_start'.
184 * Typically 'gnunet-service-arm' (but can be set to a
185 * specific service by 'GNUNET_TESTING_service_run' if
192 * Handle to the running binary of the service, NULL if the
193 * peer/service is currently not running.
195 struct GNUNET_OS_Process *main_process;
198 * The handle to the peer's ARM service
200 struct GNUNET_ARM_Handle *ah;
203 * The config of the peer
205 struct GNUNET_CONFIGURATION_Handle *cfg;
208 * The callback to call asynchronously when a peer is stopped
210 GNUNET_TESTING_PeerStopCallback cb;
213 * The closure for the above callback
218 * The cached identity of this peer. Will be populated on call to
219 * GNUNET_TESTING_peer_get_identity()
221 struct GNUNET_PeerIdentity *id;
223 struct SharedServiceInstance **ss_instances;
226 * Array of ports currently allocated to this peer. These ports will be
227 * released upon peer destroy and can be used by other peers which are
233 * The number of ports in the above array
238 * The keynumber of this peer's hostkey
245 * Testing includes a number of pre-created hostkeys for faster peer
246 * startup. This function loads such keys into memory from a file.
248 * @param system the testing system handle
249 * @return #GNUNET_OK on success; #GNUNET_SYSERR on error
252 hostkeys_load (struct GNUNET_TESTING_System *system)
257 struct GNUNET_DISK_FileHandle *fd;
259 GNUNET_assert (NULL == system->hostkeys_data);
260 data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
261 GNUNET_asprintf (&filename, "%s/testing_hostkeys.ecc", data_dir);
262 GNUNET_free (data_dir);
264 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
266 LOG (GNUNET_ERROR_TYPE_ERROR,
267 _("Hostkeys file not found: %s\n"), filename);
268 GNUNET_free (filename);
269 return GNUNET_SYSERR;
271 /* Check hostkey file size, read entire thing into memory */
273 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
277 GNUNET_free (filename);
278 return GNUNET_SYSERR; /* File is empty */
280 if (0 != (fs % GNUNET_TESTING_HOSTKEYFILESIZE))
282 LOG (GNUNET_ERROR_TYPE_ERROR,
283 _("Incorrect hostkey file format: %s\n"), filename);
284 GNUNET_free (filename);
285 return GNUNET_SYSERR;
287 fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
288 GNUNET_DISK_PERM_NONE);
291 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename);
292 GNUNET_free (filename);
293 return GNUNET_SYSERR;
295 GNUNET_free (filename);
296 system->hostkeys_data = GNUNET_DISK_file_map (fd,
298 GNUNET_DISK_MAP_TYPE_READ,
300 GNUNET_DISK_file_close (fd);
301 if (NULL == system->hostkeys_data)
302 return GNUNET_SYSERR;
303 system->total_hostkeys = fs / GNUNET_TESTING_HOSTKEYFILESIZE;
309 * Function to remove the loaded hostkeys
311 * @param system the testing system handle
314 hostkeys_unload (struct GNUNET_TESTING_System *system)
316 GNUNET_break (NULL != system->hostkeys_data);
317 system->hostkeys_data = NULL;
318 GNUNET_DISK_file_unmap (system->map);
320 system->hostkeys_data = NULL;
321 system->total_hostkeys = 0;
326 * Function to iterate over options.
329 * @param section name of the section
330 * @param option name of the option
331 * @param value value of the option
334 cfg_copy_iterator (void *cls, const char *section,
335 const char *option, const char *value)
337 struct GNUNET_CONFIGURATION_Handle *cfg2 = cls;
339 GNUNET_CONFIGURATION_set_value_string (cfg2, section, option, value);
344 * Create a system handle. There must only be one system
345 * handle per operating system.
347 * @param testdir only the directory name without any path. This is used for
348 * all service homes; the directory will be created in a temporary
349 * location depending on the underlying OS. This variable will be
350 * overridden with the value of the environmental variable
351 * GNUNET_TESTING_PREFIX, if it exists.
352 * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
353 * service configurations generated to allow control connections from
354 * this ip. This can either be a single ip address or a network address
356 * @param hostname the hostname of the system we are using for testing; NULL for
358 * @param shared_services NULL terminated array describing services that are to
359 * be shared among peers
360 * @param lowport lowest port number this system is allowed to allocate (inclusive)
361 * @param highport highest port number this system is allowed to allocate (exclusive)
362 * @return handle to this system, NULL on error
364 struct GNUNET_TESTING_System *
365 GNUNET_TESTING_system_create_with_portrange (const char *testdir,
366 const char *trusted_ip,
367 const char *hostname,
369 GNUNET_TESTING_SharedService *
374 struct GNUNET_TESTING_System *system;
375 struct GNUNET_TESTING_SharedService tss;
376 struct SharedService *ss;
379 GNUNET_assert (NULL != testdir);
380 system = GNUNET_new (struct GNUNET_TESTING_System);
381 if (NULL == (system->tmppath = getenv (GNUNET_TESTING_PREFIX)))
382 system->tmppath = GNUNET_DISK_mkdtemp (testdir);
384 system->tmppath = GNUNET_strdup (system->tmppath);
385 system->lowport = lowport;
386 system->highport = highport;
387 if (NULL == system->tmppath)
389 GNUNET_free (system);
392 if (NULL != trusted_ip)
393 system->trusted_ip = GNUNET_strdup (trusted_ip);
394 if (NULL != hostname)
395 system->hostname = GNUNET_strdup (hostname);
396 if (GNUNET_OK != hostkeys_load (system))
398 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
401 if (NULL == shared_services)
403 for (cnt = 0; NULL != shared_services[cnt].service; cnt++)
405 tss = shared_services[cnt];
406 ss = GNUNET_new (struct SharedService);
407 ss->sname = GNUNET_strdup (tss.service);
408 ss->cfg = GNUNET_CONFIGURATION_create ();
409 GNUNET_CONFIGURATION_iterate_section_values (tss.cfg, ss->sname,
410 &cfg_copy_iterator, ss->cfg);
411 GNUNET_CONFIGURATION_iterate_section_values (tss.cfg, "TESTING",
412 &cfg_copy_iterator, ss->cfg);
413 GNUNET_CONFIGURATION_iterate_section_values (tss.cfg, "PATHS",
414 &cfg_copy_iterator, ss->cfg);
415 ss->share = tss.share;
416 GNUNET_array_append (system->shared_services, system->n_shared_services,
424 * Create a system handle. There must only be one system handle per operating
425 * system. Uses a default range for allowed ports. Ports are still tested for
428 * @param testdir only the directory name without any path. This is used for all
429 * service homes; the directory will be created in a temporary location
430 * depending on the underlying OS. This variable will be
431 * overridden with the value of the environmental variable
432 * GNUNET_TESTING_PREFIX, if it exists.
433 * @param trusted_ip the ip address which will be set as TRUSTED HOST in all
434 * service configurations generated to allow control connections from
435 * this ip. This can either be a single ip address or a network address
437 * @param hostname the hostname of the system we are using for testing; NULL for
439 * @param shared_services NULL terminated array describing services that are to
440 * be shared among peers
441 * @return handle to this system, NULL on error
443 struct GNUNET_TESTING_System *
444 GNUNET_TESTING_system_create (const char *testdir,
445 const char *trusted_ip,
446 const char *hostname,
447 const struct GNUNET_TESTING_SharedService *
450 return GNUNET_TESTING_system_create_with_portrange (testdir,
460 cleanup_shared_service_instance (struct SharedServiceInstance *i)
462 if (NULL != i->cfg_fn)
464 (void) unlink (i->cfg_fn);
465 GNUNET_free (i->cfg_fn);
467 GNUNET_free_non_null (i->unix_sock);
468 GNUNET_free_non_null (i->port_str);
469 GNUNET_break (NULL == i->proc);
470 GNUNET_break (0 == i->n_refs);
476 start_shared_service_instance (struct SharedServiceInstance *i)
479 char *libexec_binary;
481 GNUNET_assert (NULL == i->proc);
482 GNUNET_assert (NULL != i->cfg_fn);
483 (void) GNUNET_asprintf (&binary, "gnunet-service-%s", i->ss->sname);
484 libexec_binary = GNUNET_OS_get_libexec_binary_path (binary);
485 GNUNET_free (binary);
486 i->proc = GNUNET_OS_start_process (PIPE_CONTROL,
487 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
494 GNUNET_free (libexec_binary);
496 return GNUNET_SYSERR;
502 stop_shared_service_instance (struct SharedServiceInstance *i)
504 GNUNET_break (0 == i->n_refs);
505 if (0 != GNUNET_OS_process_kill (i->proc, GNUNET_TERM_SIG))
506 LOG (GNUNET_ERROR_TYPE_WARNING,
507 "Killing shared service instance (%s) failed\n", i->ss->sname);
508 (void) GNUNET_OS_process_wait (i->proc);
509 GNUNET_OS_process_destroy (i->proc);
515 * Free system resources.
517 * @param system system to be freed
518 * @param remove_paths should the 'testdir' and all subdirectories
519 * be removed (clean up on shutdown)?
522 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
525 struct SharedService *ss;
526 struct SharedServiceInstance *i;
530 if (NULL != system->hostkeys_data)
531 hostkeys_unload (system);
532 for (ss_cnt = 0; ss_cnt < system->n_shared_services; ss_cnt++)
534 ss = system->shared_services[ss_cnt];
535 for (i_cnt = 0; i_cnt < ss->n_instances; i_cnt++)
537 i = ss->instances[i_cnt];
539 stop_shared_service_instance (i);
540 cleanup_shared_service_instance (i);
542 GNUNET_free_non_null (ss->instances);
543 GNUNET_CONFIGURATION_destroy (ss->cfg);
544 GNUNET_free (ss->sname);
547 GNUNET_free_non_null (system->shared_services);
548 if (GNUNET_YES == remove_paths)
549 GNUNET_DISK_directory_remove (system->tmppath);
550 GNUNET_free (system->tmppath);
551 GNUNET_free_non_null (system->trusted_ip);
552 GNUNET_free_non_null (system->hostname);
553 GNUNET_free (system);
558 * Reserve a TCP or UDP port for a peer.
560 * @param system system to use for reservation tracking
561 * @return 0 if no free port was available
564 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system)
566 struct GNUNET_NETWORK_Handle *socket;
567 struct addrinfo hint;
568 struct addrinfo *ret;
570 uint32_t *port_buckets;
579 FIXME: Instead of using getaddrinfo we should try to determine the port
580 status by the following heurestics.
582 On systems which support both IPv4 and IPv6, only ports open on both
583 address families are considered open.
584 On system with either IPv4 or IPv6. A port is considered open if it's
585 open in the respective address family
587 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
588 hint.ai_socktype = 0;
589 hint.ai_protocol = 0;
592 hint.ai_canonname = NULL;
594 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
595 port_buckets = system->reserved_ports;
596 for (index = (system->lowport / 32) + 1; index < (system->highport / 32); index++)
598 xor_image = (UINT32_MAX ^ port_buckets[index]);
599 if (0 == xor_image) /* Ports in the bucket are full */
601 pos = system->lowport % 32;
604 if (0 == ((xor_image >> pos) & 1U))
609 open_port = (index * 32) + pos;
610 if (open_port >= system->highport)
612 GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
614 GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
615 GNUNET_free (open_port_str);
616 bind_status = GNUNET_NO;
617 for (ai = ret; NULL != ai; ai = ai->ai_next)
619 socket = GNUNET_NETWORK_socket_create (ai->ai_family, SOCK_STREAM, 0);
622 bind_status = GNUNET_NETWORK_socket_bind (socket,
625 GNUNET_NETWORK_socket_close (socket);
626 if (GNUNET_OK != bind_status)
628 socket = GNUNET_NETWORK_socket_create (ai->ai_family, SOCK_DGRAM, 0);
631 bind_status = GNUNET_NETWORK_socket_bind (socket,
634 GNUNET_NETWORK_socket_close (socket);
635 if (GNUNET_OK != bind_status)
638 port_buckets[index] |= (1U << pos); /* Set the port bit */
640 if (GNUNET_OK == bind_status)
642 LOG (GNUNET_ERROR_TYPE_DEBUG,
643 "Found a free port %u\n", (unsigned int) open_port);
654 * Release reservation of a TCP or UDP port for a peer
655 * (used during #GNUNET_TESTING_peer_destroy()).
657 * @param system system to use for reservation tracking
658 * @param port reserved port to release
661 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
664 uint32_t *port_buckets;
668 port_buckets = system->reserved_ports;
671 LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
672 if (0 == (port_buckets[bucket] & (1U << pos)))
674 GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
677 port_buckets[bucket] &= ~(1U << pos);
682 * Testing includes a number of pre-created hostkeys for
683 * faster peer startup. This function can be used to
684 * access the n-th key of those pre-created hostkeys; note
685 * that these keys are ONLY useful for testing and not
686 * secure as the private keys are part of the public
687 * GNUnet source code.
689 * This is primarily a helper function used internally
690 * by #GNUNET_TESTING_peer_configure.
692 * @param system the testing system handle
693 * @param key_number desired pre-created hostkey to obtain
694 * @param id set to the peer's identity (hash of the public
695 * key; if NULL, NULL is returned immediately
696 * @return NULL on error (not enough keys)
698 struct GNUNET_CRYPTO_EddsaPrivateKey *
699 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
701 struct GNUNET_PeerIdentity *id)
703 struct GNUNET_CRYPTO_EddsaPrivateKey *private_key;
705 if ((NULL == id) || (NULL == system->hostkeys_data))
707 if (key_number >= system->total_hostkeys)
709 LOG (GNUNET_ERROR_TYPE_ERROR,
710 _("Key number %u does not exist\n"),
714 private_key = GNUNET_new (struct GNUNET_CRYPTO_EddsaPrivateKey);
715 GNUNET_memcpy (private_key,
716 system->hostkeys_data +
717 (key_number * GNUNET_TESTING_HOSTKEYFILESIZE),
718 GNUNET_TESTING_HOSTKEYFILESIZE);
719 GNUNET_CRYPTO_eddsa_key_get_public (private_key,
726 * Structure for holding data to build new configurations from a configuration
732 * The system for which we are building configurations
734 struct GNUNET_TESTING_System *system;
737 * The configuration we are building
739 struct GNUNET_CONFIGURATION_Handle *cfg;
742 * The customized service home path for this peer
747 * Array of ports currently allocated to this peer. These ports will be
748 * released upon peer destroy and can be used by other peers which are
754 * The number of ports in the above array
759 * build status - to signal error while building a configuration
766 * Function to iterate over options. Copies
767 * the options to the target configuration,
768 * updating PORT values as needed.
770 * @param cls the UpdateContext
771 * @param section name of the section
772 * @param option name of the option
773 * @param value value of the option
776 update_config (void *cls,
781 struct UpdateContext *uc = cls;
785 char *single_variable;
786 char *per_host_variable;
787 unsigned long long num_per_host;
790 if (GNUNET_OK != uc->status)
792 if (! ((0 == strcmp (option, "PORT"))
793 || (0 == strcmp (option, "UNIXPATH"))
794 || (0 == strcmp (option, "HOSTNAME"))))
796 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
797 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
798 if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
802 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
805 new_port = GNUNET_TESTING_reserve_port (uc->system);
808 uc->status = GNUNET_SYSERR;
809 GNUNET_free (single_variable);
810 GNUNET_free (per_host_variable);
813 GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
815 GNUNET_array_append (uc->ports, uc->nports, new_port);
817 else if ((ival != 0) &&
819 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
821 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
825 /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
826 /* ival + ctx->fdnum % num_per_host); */
828 GNUNET_break (0); /* FIXME */
831 if (0 == strcmp (option, "UNIXPATH"))
834 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
837 GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock",
838 uc->gnunet_home, section);
841 else if ((GNUNET_YES ==
842 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
847 GNUNET_break(0); /* FIXME */
850 if (0 == strcmp (option, "HOSTNAME"))
852 value = (NULL == uc->system->hostname) ? "localhost" : uc->system->hostname;
854 GNUNET_free (single_variable);
855 GNUNET_free (per_host_variable);
856 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
861 * Section iterator to set ACCEPT_FROM/ACCEPT_FROM6 to include the address of
862 * 'trusted_hosts' in all sections
864 * @param cls the UpdateContext
865 * @param section name of the section
868 update_config_sections (void *cls,
871 struct UpdateContext *uc = cls;
875 char *orig_allowed_hosts;
877 char *ACCEPT_FROM_key;
883 /* Ignore certain options from sections. See
884 https://gnunet.org/bugs/view.php?id=2476 */
885 if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
886 "TESTING_IGNORE_KEYS"))
890 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section,
891 "TESTING_IGNORE_KEYS", &val));
893 for (ikeys_cnt = 0; NULL != (ptr = strstr (ptr, ";")); ikeys_cnt++)
899 ikeys = GNUNET_malloc ((sizeof (char *)) * ikeys_cnt);
901 for (key = 0; key < ikeys_cnt; key++)
904 ptr = strstr (ptr, ";");
905 GNUNET_assert (NULL != ptr); /* worked just before... */
913 for (key = 0; key < ikeys_cnt; key++)
915 if (NULL != strstr (ikeys[key], "ADVERTISED_PORT"))
918 if ((key == ikeys_cnt) &&
919 (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section,
923 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "PORT", &ptr))
925 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section,
926 "ADVERTISED_PORT", ptr);
930 for (key = 0; key < ikeys_cnt; key++)
932 if (NULL != strstr (ikeys[key], "ACCEPT_FROM"))
941 GNUNET_free_non_null (val);
942 ACCEPT_FROM_key = "ACCEPT_FROM";
943 if ((NULL != uc->system->trusted_ip) &&
944 (NULL != strstr (uc->system->trusted_ip, ":"))) /* IPv6 in use */
945 ACCEPT_FROM_key = "ACCEPT_FROM6";
947 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, ACCEPT_FROM_key,
948 &orig_allowed_hosts))
950 orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
952 if (NULL == uc->system->trusted_ip)
953 allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
955 GNUNET_asprintf (&allowed_hosts, "%s%s;", orig_allowed_hosts,
956 uc->system->trusted_ip);
957 GNUNET_free (orig_allowed_hosts);
958 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, ACCEPT_FROM_key,
960 GNUNET_free (allowed_hosts);
964 static struct SharedServiceInstance *
965 associate_shared_service (struct GNUNET_TESTING_System *system,
966 struct SharedService *ss,
967 struct GNUNET_CONFIGURATION_Handle *cfg)
969 struct SharedServiceInstance *i;
970 struct GNUNET_CONFIGURATION_Handle *temp;
975 if ( ((0 == ss->share) && (NULL == ss->instances))
978 && (ss->n_instances < ((ss->n_peers + ss->share - 1) / ss->share)) ) )
980 i = GNUNET_new (struct SharedServiceInstance);
982 (void) GNUNET_asprintf (&gnunet_home, "%s/shared/%s/%u",
983 system->tmppath, ss->sname, ss->n_instances);
984 (void) GNUNET_asprintf (&i->unix_sock, "%s/sock", gnunet_home);
985 port = GNUNET_TESTING_reserve_port (system);
988 GNUNET_free (gnunet_home);
989 cleanup_shared_service_instance (i);
992 GNUNET_array_append (ss->instances, ss->n_instances, i);
993 temp = GNUNET_CONFIGURATION_dup (ss->cfg);
994 (void) GNUNET_asprintf (&i->port_str, "%u", port);
995 (void) GNUNET_asprintf (&i->cfg_fn, "%s/config", gnunet_home);
996 GNUNET_CONFIGURATION_set_value_string (temp, "PATHS", "GNUNET_HOME",
998 GNUNET_free (gnunet_home);
999 GNUNET_CONFIGURATION_set_value_string (temp, ss->sname, "UNIXPATH",
1001 GNUNET_CONFIGURATION_set_value_string (temp, ss->sname, "PORT",
1003 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_write (temp, i->cfg_fn))
1005 GNUNET_CONFIGURATION_destroy (temp);
1006 cleanup_shared_service_instance (i);
1009 GNUNET_CONFIGURATION_destroy (temp);
1013 GNUNET_assert (NULL != ss->instances);
1014 GNUNET_assert (0 < ss->n_instances);
1015 i = ss->instances[ss->n_instances - 1];
1017 GNUNET_CONFIGURATION_iterate_section_values(ss->cfg, ss->sname,
1018 &cfg_copy_iterator, cfg);
1019 GNUNET_CONFIGURATION_set_value_string (cfg, ss->sname, "UNIXPATH",
1021 GNUNET_CONFIGURATION_set_value_string (cfg, ss->sname, "PORT", i->port_str);
1027 * Create a new configuration using the given configuration as a template;
1028 * ports and paths will be modified to select available ports on the local
1029 * system. The default configuration will be available in PATHS section under
1030 * the option DEFAULTCONFIG after the call. GNUNET_HOME is also set in PATHS
1031 * section to the temporary directory specific to this configuration. If we run
1032 * out of "*port" numbers, return #GNUNET_SYSERR.
1034 * This is primarily a helper function used internally
1035 * by 'GNUNET_TESTING_peer_configure'.
1037 * @param system system to use to coordinate resource usage
1038 * @param cfg template configuration to update
1039 * @param ports array with port numbers used in the created configuration.
1040 * Will be updated upon successful return. Can be NULL
1041 * @param nports the size of the `ports' array. Will be updated.
1042 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - the configuration will
1043 * be incomplete and should not be used there upon
1046 GNUNET_TESTING_configuration_create_ (struct GNUNET_TESTING_System *system,
1047 struct GNUNET_CONFIGURATION_Handle *cfg,
1049 unsigned int *nports)
1051 struct UpdateContext uc;
1052 char *default_config;
1056 uc.status = GNUNET_OK;
1059 GNUNET_asprintf (&uc.gnunet_home, "%s/%u", system->tmppath,
1060 system->path_counter++);
1061 GNUNET_asprintf (&default_config, "%s/config", uc.gnunet_home);
1062 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
1064 GNUNET_CONFIGURATION_set_value_string (cfg, "arm", "CONFIG",
1066 GNUNET_free (default_config);
1067 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "GNUNET_HOME",
1069 /* make PORTs and UNIXPATHs unique */
1070 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
1071 /* allow connections to services from system trusted_ip host */
1072 GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
1073 /* enable loopback-based connections between peers */
1074 GNUNET_CONFIGURATION_set_value_string (cfg,
1076 "USE_LOCALADDR", "YES");
1077 GNUNET_free (uc.gnunet_home);
1078 if ((NULL != ports) && (NULL != nports))
1081 *nports = uc.nports;
1084 GNUNET_free_non_null (uc.ports);
1090 * Create a new configuration using the given configuration as a template;
1091 * ports and paths will be modified to select available ports on the local
1092 * system. The default configuration will be available in PATHS section under
1093 * the option DEFAULTCONFIG after the call. GNUNET_HOME is also set in PATHS
1094 * section to the temporary directory specific to this configuration. If we run
1095 * out of "*port" numbers, return #GNUNET_SYSERR.
1097 * This is primarily a helper function used internally
1098 * by #GNUNET_TESTING_peer_configure().
1100 * @param system system to use to coordinate resource usage
1101 * @param cfg template configuration to update
1102 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - the configuration will
1103 * be incomplete and should not be used there upon
1106 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
1107 struct GNUNET_CONFIGURATION_Handle *cfg)
1109 return GNUNET_TESTING_configuration_create_ (system, cfg, NULL, NULL);
1114 * Configure a GNUnet peer. GNUnet must be installed on the local
1115 * system and available in the PATH.
1117 * @param system system to use to coordinate resource usage
1118 * @param cfg configuration to use; will be UPDATED (to reflect needed
1119 * changes in port numbers and paths)
1120 * @param key_number number of the hostkey to use for the peer
1121 * @param id identifier for the daemon, will be set, can be NULL
1122 * @param emsg set to freshly allocated error message (set to NULL on success),
1124 * @return handle to the peer, NULL on error
1126 struct GNUNET_TESTING_Peer *
1127 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
1128 struct GNUNET_CONFIGURATION_Handle *cfg,
1129 uint32_t key_number,
1130 struct GNUNET_PeerIdentity *id,
1133 struct GNUNET_TESTING_Peer *peer;
1134 struct GNUNET_DISK_FileHandle *fd;
1135 char *hostkey_filename;
1136 char *config_filename;
1137 char *libexec_binary;
1139 struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
1141 struct SharedService *ss;
1142 struct SharedServiceInstance **ss_instances;
1144 unsigned int nports;
1148 ss_instances = NULL;
1151 if (key_number >= system->total_hostkeys)
1153 GNUNET_asprintf (&emsg_,
1154 _("You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"),
1155 (unsigned int) system->total_hostkeys);
1160 (NULL == (pk = GNUNET_TESTING_hostkey_get (system, key_number, id))))
1162 GNUNET_asprintf (&emsg_,
1163 _("Failed to initialize hostkey for peer %u\n"),
1164 (unsigned int) key_number);
1170 GNUNET_CONFIGURATION_have_value (cfg, "PEER", "PRIVATE_KEY"))
1172 GNUNET_asprintf (&emsg_,
1173 _("PRIVATE_KEY option in PEER section missing in configuration\n"));
1176 /* Remove sections for shared services */
1177 for (cnt = 0; cnt < system->n_shared_services; cnt++)
1179 ss = system->shared_services[cnt];
1180 GNUNET_CONFIGURATION_remove_section (cfg, ss->sname);
1182 if (GNUNET_OK != GNUNET_TESTING_configuration_create_ (system, cfg,
1185 GNUNET_asprintf (&emsg_,
1186 _("Failed to create configuration for peer "
1187 "(not enough free ports?)\n"));
1190 GNUNET_assert (GNUNET_OK ==
1191 GNUNET_CONFIGURATION_get_value_filename (cfg, "PEER",
1193 &hostkey_filename));
1194 fd = GNUNET_DISK_file_open (hostkey_filename,
1195 GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
1196 GNUNET_DISK_PERM_USER_READ
1197 | GNUNET_DISK_PERM_USER_WRITE);
1200 GNUNET_asprintf (&emsg_, _("Cannot open hostkey file `%s': %s\n"),
1201 hostkey_filename, STRERROR (errno));
1202 GNUNET_free (hostkey_filename);
1205 GNUNET_free (hostkey_filename);
1206 if (GNUNET_TESTING_HOSTKEYFILESIZE !=
1207 GNUNET_DISK_file_write (fd, system->hostkeys_data
1208 + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE),
1209 GNUNET_TESTING_HOSTKEYFILESIZE))
1211 GNUNET_asprintf (&emsg_,
1212 _("Failed to write hostkey file for peer %u: %s\n"),
1213 (unsigned int) key_number,
1215 GNUNET_DISK_file_close (fd);
1218 GNUNET_DISK_file_close (fd);
1219 ss_instances = GNUNET_malloc (sizeof (struct SharedServiceInstance *)
1220 * system->n_shared_services);
1221 for (cnt=0; cnt < system->n_shared_services; cnt++)
1223 ss = system->shared_services[cnt];
1224 ss_instances[cnt] = associate_shared_service (system, ss, cfg);
1225 if (NULL == ss_instances[cnt])
1227 emsg_ = GNUNET_strdup ("FIXME");
1231 GNUNET_assert (GNUNET_OK ==
1232 GNUNET_CONFIGURATION_get_value_filename
1233 (cfg, "PATHS", "DEFAULTCONFIG", &config_filename));
1234 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
1236 GNUNET_asprintf (&emsg_,
1237 _("Failed to write configuration file `%s' for peer %u: %s\n"),
1239 (unsigned int) key_number,
1241 GNUNET_free (config_filename);
1244 peer = GNUNET_new (struct GNUNET_TESTING_Peer);
1245 peer->ss_instances = ss_instances;
1246 peer->cfgfile = config_filename; /* Free in peer_destroy */
1247 peer->cfg = GNUNET_CONFIGURATION_dup (cfg);
1248 libexec_binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
1249 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "arm", "PREFIX", &peer->main_binary))
1252 GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1253 peer->args = GNUNET_strdup ("");
1257 peer->args = GNUNET_strdup (libexec_binary);
1259 peer->system = system;
1260 peer->key_number = key_number;
1261 GNUNET_free (libexec_binary);
1262 peer->ports = ports; /* Free in peer_destroy */
1263 peer->nports = nports;
1267 GNUNET_free_non_null (ss_instances);
1268 GNUNET_free_non_null (ports);
1269 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
1273 GNUNET_free (emsg_);
1279 * Obtain the peer identity from a peer handle.
1281 * @param peer peer handle for which we want the peer's identity
1282 * @param id identifier for the daemon, will be set
1285 GNUNET_TESTING_peer_get_identity (struct GNUNET_TESTING_Peer *peer,
1286 struct GNUNET_PeerIdentity *id)
1288 if (NULL != peer->id)
1290 GNUNET_memcpy (id, peer->id, sizeof (struct GNUNET_PeerIdentity));
1293 peer->id = GNUNET_new (struct GNUNET_PeerIdentity);
1294 GNUNET_free (GNUNET_TESTING_hostkey_get (peer->system,
1297 GNUNET_memcpy (id, peer->id, sizeof (struct GNUNET_PeerIdentity));
1304 * @param peer peer to start
1305 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (i.e. peer already running)
1308 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
1310 struct SharedServiceInstance *i;
1313 if (NULL != peer->main_process)
1316 return GNUNET_SYSERR;
1318 GNUNET_assert (NULL != peer->cfgfile);
1319 for (cnt = 0; cnt < peer->system->n_shared_services; cnt++)
1321 i = peer->ss_instances[cnt];
1322 if ((0 == i->n_refs)
1323 && (GNUNET_SYSERR == start_shared_service_instance (i)) )
1324 return GNUNET_SYSERR;
1327 peer->main_binary = GNUNET_CONFIGURATION_expand_dollar (peer->cfg, peer->main_binary);
1328 peer->main_process = GNUNET_OS_start_process_s (PIPE_CONTROL,
1329 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
1336 if (NULL == peer->main_process)
1338 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1339 _("Failed to start `%s': %s\n"),
1342 return GNUNET_SYSERR;
1349 * Sends SIGTERM to the peer's main process
1351 * @param peer the handle to the peer
1352 * @return #GNUNET_OK if successful; #GNUNET_SYSERR if the main process is NULL
1353 * or upon any error while sending SIGTERM
1356 GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer)
1358 struct SharedServiceInstance *i;
1361 if (NULL == peer->main_process)
1364 return GNUNET_SYSERR;
1366 if (0 != GNUNET_OS_process_kill (peer->main_process, GNUNET_TERM_SIG))
1367 return GNUNET_SYSERR;
1368 for (cnt = 0; cnt < peer->system->n_shared_services; cnt++)
1370 i = peer->ss_instances[cnt];
1371 GNUNET_assert (0 != i->n_refs);
1374 stop_shared_service_instance (i);
1381 * Waits for a peer to terminate. The peer's main process will also be destroyed.
1383 * @param peer the handle to the peer
1384 * @return #GNUNET_OK if successful; #GNUNET_SYSERR if the main process is NULL
1385 * or upon any error while waiting
1388 GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer)
1392 if (NULL == peer->main_process)
1395 return GNUNET_SYSERR;
1397 ret = GNUNET_OS_process_wait (peer->main_process);
1398 GNUNET_OS_process_destroy (peer->main_process);
1399 peer->main_process = NULL;
1407 * @param peer peer to stop
1408 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1411 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
1413 if (GNUNET_SYSERR == GNUNET_TESTING_peer_kill (peer))
1414 return GNUNET_SYSERR;
1415 if (GNUNET_SYSERR == GNUNET_TESTING_peer_wait (peer))
1416 return GNUNET_SYSERR;
1422 * Function called whenever we connect to or disconnect from ARM.
1424 * @param cls closure
1425 * @param connected #GNUNET_YES if connected, #GNUNET_NO if disconnected,
1426 * #GNUNET_SYSERR on error.
1429 disconn_status (void *cls,
1432 struct GNUNET_TESTING_Peer *peer = cls;
1434 if (GNUNET_SYSERR == connected)
1436 peer->cb (peer->cb_cls, peer, connected);
1439 if (GNUNET_YES == connected)
1441 GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_kill (peer));
1444 GNUNET_break (GNUNET_OK == GNUNET_TESTING_peer_wait (peer));
1445 GNUNET_ARM_disconnect (peer->ah);
1447 peer->cb (peer->cb_cls, peer, GNUNET_YES);
1452 * Stop a peer asynchronously using ARM API. Peer's shutdown is signaled
1453 * through the GNUNET_TESTING_PeerStopCallback().
1455 * @param peer the peer to stop
1456 * @param cb the callback to signal peer shutdown
1457 * @param cb_cls closure for the above callback
1458 * @return #GNUNET_OK upon successfully giving the request to the ARM API (this
1459 * does not mean that the peer is successfully stopped); #GNUNET_SYSERR
1463 GNUNET_TESTING_peer_stop_async (struct GNUNET_TESTING_Peer *peer,
1464 GNUNET_TESTING_PeerStopCallback cb,
1467 if (NULL == peer->main_process)
1468 return GNUNET_SYSERR;
1469 peer->ah = GNUNET_ARM_connect (peer->cfg, &disconn_status, peer);
1470 if (NULL == peer->ah)
1471 return GNUNET_SYSERR;
1473 peer->cb_cls = cb_cls;
1479 * Cancel a previous asynchronous peer stop request.
1480 * GNUNET_TESTING_peer_stop_async() should have been called before on the given
1481 * peer. It is an error to call this function if the peer stop callback was
1484 * @param peer the peer on which GNUNET_TESTING_peer_stop_async() was called
1488 GNUNET_TESTING_peer_stop_async_cancel (struct GNUNET_TESTING_Peer *peer)
1490 GNUNET_assert (NULL != peer->ah);
1491 GNUNET_ARM_disconnect (peer->ah);
1497 * Destroy the peer. Releases resources locked during peer configuration.
1498 * If the peer is still running, it will be stopped AND a warning will be
1499 * printed (users of the API should stop the peer explicitly first).
1501 * @param peer peer to destroy
1504 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
1508 if (NULL != peer->main_process)
1509 GNUNET_TESTING_peer_stop (peer);
1510 if (NULL != peer->ah)
1511 GNUNET_ARM_disconnect (peer->ah);
1512 GNUNET_free (peer->cfgfile);
1513 if (NULL != peer->cfg)
1514 GNUNET_CONFIGURATION_destroy (peer->cfg);
1515 GNUNET_free (peer->main_binary);
1516 GNUNET_free (peer->args);
1517 GNUNET_free_non_null (peer->id);
1518 GNUNET_free_non_null (peer->ss_instances);
1519 if (NULL != peer->ports)
1521 for (cnt = 0; cnt < peer->nports; cnt++)
1522 GNUNET_TESTING_release_port (peer->system, peer->ports[cnt]);
1523 GNUNET_free (peer->ports);
1530 * Start a single peer and run a test using the testing library.
1531 * Starts a peer using the given configuration and then invokes the
1532 * given callback. This function ALSO initializes the scheduler loop
1533 * and should thus be called directly from "main". The testcase
1534 * should self-terminate by invoking #GNUNET_SCHEDULER_shutdown().
1536 * @param testdir only the directory name without any path. This is used for
1537 * all service homes; the directory will be created in a temporary
1538 * location depending on the underlying OS
1539 * @param cfgfilename name of the configuration file to use;
1540 * use NULL to only run with defaults
1541 * @param tm main function of the testcase
1542 * @param tm_cls closure for @a tm
1543 * @return 0 on success, 1 on error
1546 GNUNET_TESTING_peer_run (const char *testdir,
1547 const char *cfgfilename,
1548 GNUNET_TESTING_TestMain tm,
1551 return GNUNET_TESTING_service_run (testdir, "arm",
1552 cfgfilename, tm, tm_cls);
1557 * Structure for holding service data
1559 struct ServiceContext
1562 * The configuration of the peer in which the service is run
1564 const struct GNUNET_CONFIGURATION_Handle *cfg;
1567 * Callback to signal service startup
1569 GNUNET_TESTING_TestMain tm;
1572 * The peer in which the service is run.
1574 struct GNUNET_TESTING_Peer *peer;
1577 * Closure for the above callback
1584 * Callback to be called when SCHEDULER has been started
1586 * @param cls the ServiceContext
1589 service_run_main (void *cls)
1591 struct ServiceContext *sc = cls;
1593 sc->tm (sc->tm_cls, sc->cfg, sc->peer);
1598 * Start a single service (no ARM, except of course if the given
1599 * service name is 'arm') and run a test using the testing library.
1600 * Starts a service using the given configuration and then invokes the
1601 * given callback. This function ALSO initializes the scheduler loop
1602 * and should thus be called directly from "main". The testcase
1603 * should self-terminate by invoking #GNUNET_SCHEDULER_shutdown().
1605 * This function is useful if the testcase is for a single service
1606 * and if that service doesn't itself depend on other services.
1608 * @param testdir only the directory name without any path. This is used for
1609 * all service homes; the directory will be created in a temporary
1610 * location depending on the underlying OS
1611 * @param service_name name of the service to run
1612 * @param cfgfilename name of the configuration file to use;
1613 * use NULL to only run with defaults
1614 * @param tm main function of the testcase
1615 * @param tm_cls closure for @a tm
1616 * @return 0 on success, 1 on error
1619 GNUNET_TESTING_service_run (const char *testdir,
1620 const char *service_name,
1621 const char *cfgfilename,
1622 GNUNET_TESTING_TestMain tm,
1625 struct ServiceContext sc;
1626 struct GNUNET_TESTING_System *system;
1627 struct GNUNET_TESTING_Peer *peer;
1628 struct GNUNET_CONFIGURATION_Handle *cfg;
1630 char *libexec_binary;
1632 GNUNET_log_setup (testdir,
1635 system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL, NULL);
1638 cfg = GNUNET_CONFIGURATION_create ();
1639 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1641 LOG (GNUNET_ERROR_TYPE_ERROR,
1642 _("Failed to load configuration from %s\n"), cfgfilename);
1643 GNUNET_CONFIGURATION_destroy (cfg);
1644 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1647 peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1650 GNUNET_CONFIGURATION_destroy (cfg);
1651 hostkeys_unload (system);
1652 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1655 GNUNET_free (peer->main_binary);
1656 GNUNET_free (peer->args);
1657 GNUNET_asprintf (&binary, "gnunet-service-%s", service_name);
1658 libexec_binary = GNUNET_OS_get_libexec_binary_path (binary);
1659 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, service_name, "PREFIX", &peer->main_binary))
1662 GNUNET_asprintf(&peer->main_binary, "%s", libexec_binary);
1663 peer->args = GNUNET_strdup ("");
1666 peer->args = GNUNET_strdup (libexec_binary);
1668 GNUNET_free (libexec_binary);
1669 GNUNET_free (binary);
1670 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1672 GNUNET_TESTING_peer_destroy (peer);
1673 GNUNET_CONFIGURATION_destroy (cfg);
1674 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1681 GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1682 if ((NULL != peer->main_process) &&
1683 (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)))
1685 GNUNET_TESTING_peer_destroy (peer);
1686 GNUNET_CONFIGURATION_destroy (cfg);
1687 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1690 GNUNET_TESTING_peer_destroy (peer);
1691 GNUNET_CONFIGURATION_destroy (cfg);
1692 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1698 * Sometimes we use the binary name to determine which specific
1699 * test to run. In those cases, the string after the last "_"
1700 * in 'argv[0]' specifies a string that determines the configuration
1701 * file or plugin to use.
1703 * This function returns the respective substring, taking care
1704 * of issues such as binaries ending in '.exe' on W32.
1706 * @param argv0 the name of the binary
1707 * @return string between the last '_' and the '.exe' (or the end of the string),
1708 * NULL if argv0 has no '_'
1711 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1713 size_t slen = strlen (argv0) + 1;
1718 GNUNET_memcpy (sbuf, argv0, slen);
1719 ret = strrchr (sbuf, '_');
1722 ret++; /* skip underscore */
1723 dot = strchr (ret, '.');
1726 return GNUNET_strdup (ret);
1730 /* end of testing.c */