X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Ftesting%2Ftesting.c;h=f4df6d48c45376ee82691f38db44c150502bf63a;hb=f4d040c0f0dd2fef3d73b1f4532c76219f760f75;hp=3e6cbbb0ed9aec1a038a21a1b6553e022d95e821;hpb=bd8ba044e2d6d9878b6a24eceb89b29965d08cf3;p=oweals%2Fgnunet.git diff --git a/src/testing/testing.c b/src/testing/testing.c index 3e6cbbb0e..f4df6d48c 100644 --- a/src/testing/testing.c +++ b/src/testing/testing.c @@ -34,12 +34,7 @@ #include "gnunet_testing_lib-new.h" #define LOG(kind,...) \ - GNUNET_log_from (kind, "gnunettestingnew", __VA_ARGS__) - -/** - * Size of a hostkey when written to a file - */ -#define HOSTKEYFILESIZE 914 + GNUNET_log_from (kind, "testing-api", __VA_ARGS__) /** * Lowest port used for GNUnet testing. Should be high enough to not @@ -74,7 +69,12 @@ struct GNUNET_TESTING_System char *controller; /** - * Hostkeys data, contains "HOSTKEYFILESIZE * total_hostkeys" bytes. + * our hostname + */ + char *hostname; + + /** + * Hostkeys data, contains "GNUNET_TESTING_HOSTKEYFILESIZE * total_hostkeys" bytes. */ char *hostkeys_data; @@ -124,6 +124,16 @@ struct GNUNET_TESTING_System * The number of hostkeys */ uint32_t total_hostkeys; + + /** + * Lowest port we are allowed to use. + */ + uint16_t lowport; + + /** + * Highest port we are allowed to use. + */ + uint16_t highport; }; @@ -132,6 +142,10 @@ struct GNUNET_TESTING_System */ struct GNUNET_TESTING_Peer { + /** + * The TESTING system associated with this peer + */ + struct GNUNET_TESTING_System *system; /** * Path to the configuration file for this peer. @@ -151,6 +165,11 @@ struct GNUNET_TESTING_Peer * peer/service is currently not running. */ struct GNUNET_OS_Process *main_process; + + /** + * The keynumber of this peer's hostkey + */ + uint32_t key_number; }; @@ -189,7 +208,7 @@ hostkeys_load (struct GNUNET_TESTING_System *system) GNUNET_free (filename); return GNUNET_SYSERR; /* File is empty */ } - if (0 != (fs % HOSTKEYFILESIZE)) + if (0 != (fs % GNUNET_TESTING_HOSTKEYFILESIZE)) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Incorrect hostkey file format: %s\n"), filename); @@ -204,7 +223,7 @@ hostkeys_load (struct GNUNET_TESTING_System *system) GNUNET_free (filename); return GNUNET_SYSERR; } - system->total_hostkeys = fs / HOSTKEYFILESIZE; + system->total_hostkeys = fs / GNUNET_TESTING_HOSTKEYFILESIZE; system->hostkeys_data = GNUNET_DISK_file_map (system->map_fd, &system->map, GNUNET_DISK_MAP_TYPE_READ, @@ -240,21 +259,29 @@ hostkeys_unload (struct GNUNET_TESTING_System *system) * @param testdir only the directory name without any path. This is used for * all service homes; the directory will be created in a temporary * location depending on the underlying OS - * * @param controller hostname of the controlling host, * service configurations are modified to allow * control connections from this host; can be NULL + * @param hostname the hostname of the system we are using for testing; NULL for + * localhost + * @param lowport lowest port number this system is allowed to allocate (inclusive) + * @param highport highest port number this system is allowed to allocate (exclusive) * @return handle to this system, NULL on error */ struct GNUNET_TESTING_System * -GNUNET_TESTING_system_create (const char *testdir, - const char *controller) +GNUNET_TESTING_system_create_with_portrange (const char *testdir, + const char *controller, + const char *hostname, + uint16_t lowport, + uint16_t highport) { struct GNUNET_TESTING_System *system; GNUNET_assert (NULL != testdir); system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System)); system->tmppath = GNUNET_DISK_mkdtemp (testdir); + system->lowport = lowport; + system->highport = highport; if (NULL == system->tmppath) { GNUNET_free (system); @@ -262,6 +289,8 @@ GNUNET_TESTING_system_create (const char *testdir, } if (NULL != controller) system->controller = GNUNET_strdup (controller); + if (NULL != hostname) + system->hostname = GNUNET_strdup (hostname); if (GNUNET_OK != hostkeys_load (system)) { GNUNET_TESTING_system_destroy (system, GNUNET_YES); @@ -271,6 +300,33 @@ GNUNET_TESTING_system_create (const char *testdir, } +/** + * Create a system handle. There must only be one system handle per operating + * system. Uses a default range for allowed ports. Ports are still tested for + * availability. + * + * @param testdir only the directory name without any path. This is used for all + * service homes; the directory will be created in a temporary location + * depending on the underlying OS + * @param controller hostname of the controlling host, service configurations + * are modified to allow control connections from this host; can be NULL + * @param hostname the hostname of the system we are using for testing; NULL for + * localhost + * @return handle to this system, NULL on error + */ +struct GNUNET_TESTING_System * +GNUNET_TESTING_system_create (const char *testdir, + const char *controller, + const char *hostname) +{ + return GNUNET_TESTING_system_create_with_portrange (testdir, + controller, + hostname, + LOW_PORT, + HIGH_PORT); +} + + /** * Free system resources. * @@ -288,6 +344,7 @@ GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system, GNUNET_DISK_directory_remove (system->tmppath); GNUNET_free (system->tmppath); GNUNET_free_non_null (system->controller); + GNUNET_free_non_null (system->hostname); GNUNET_free (system); } @@ -306,6 +363,7 @@ GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system, struct GNUNET_NETWORK_Handle *socket; struct addrinfo hint; struct addrinfo *ret; + struct addrinfo *ai; uint32_t *port_buckets; char *open_port_str; int bind_status; @@ -333,12 +391,12 @@ GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system, hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */ port_buckets = (GNUNET_YES == is_tcp) ? system->reserved_tcp_ports : system->reserved_udp_ports; - for (index = (LOW_PORT / 32) + 1; index < (HIGH_PORT / 32); index++) + for (index = (system->lowport / 32) + 1; index < (system->highport / 32); index++) { xor_image = (UINT32_MAX ^ port_buckets[index]); if (0 == xor_image) /* Ports in the bucket are full */ continue; - pos = 0; + pos = system->lowport % 32; while (pos < 32) { if (0 == ((xor_image >> pos) & 1U)) @@ -347,22 +405,30 @@ GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system, continue; } open_port = (index * 32) + pos; + if (open_port >= system->highport) + return 0; GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port); ret = NULL; GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret)); - GNUNET_free (open_port_str); - socket = GNUNET_NETWORK_socket_create (ret->ai_family, - (GNUNET_YES == is_tcp) ? - SOCK_STREAM : SOCK_DGRAM, - 0); - GNUNET_assert (NULL != socket); - bind_status = GNUNET_NETWORK_socket_bind (socket, - ret->ai_addr, - ret->ai_addrlen); - freeaddrinfo (ret); - GNUNET_NETWORK_socket_close (socket); - socket = NULL; + GNUNET_free (open_port_str); + bind_status = GNUNET_NO; + for (ai = ret; NULL != ai; ai = ai->ai_next) + { + socket = GNUNET_NETWORK_socket_create (ai->ai_family, + (GNUNET_YES == is_tcp) ? + SOCK_STREAM : SOCK_DGRAM, + 0); + if (NULL == socket) + continue; + bind_status = GNUNET_NETWORK_socket_bind (socket, + ai->ai_addr, + ai->ai_addrlen); + GNUNET_NETWORK_socket_close (socket); + if (GNUNET_OK != bind_status) + break; + } port_buckets[index] |= (1U << pos); /* Set the port bit */ + freeaddrinfo (ret); if (GNUNET_OK == bind_status) { LOG (GNUNET_ERROR_TYPE_DEBUG, @@ -460,8 +526,9 @@ GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system, return NULL; } private_key = GNUNET_CRYPTO_rsa_decode_key (system->hostkeys_data + - (key_number * HOSTKEYFILESIZE), - HOSTKEYFILESIZE); + (key_number * + GNUNET_TESTING_HOSTKEYFILESIZE), + GNUNET_TESTING_HOSTKEYFILESIZE); if (NULL == private_key) { LOG (GNUNET_ERROR_TYPE_ERROR, @@ -585,9 +652,9 @@ update_config (void *cls, const char *section, const char *option, GNUNET_break(0); /* FIXME */ } } - if ((0 == strcmp (option, "HOSTNAME")) && (NULL != uc->system->controller)) + if (0 == strcmp (option, "HOSTNAME")) { - value = uc->system->controller; + value = (NULL == uc->system->hostname) ? "localhost" : uc->system->hostname; } GNUNET_free (single_variable); GNUNET_free (per_host_variable); @@ -596,7 +663,8 @@ update_config (void *cls, const char *section, const char *option, /** - * Section iterator to set ACCEPT_FROM in all sections + * Section iterator to set ACCEPT_FROM/ACCEPT_FROM6 depending on the ip of the + * controller in all sections * * @param cls the UpdateContext * @param section name of the section @@ -605,12 +673,80 @@ static void update_config_sections (void *cls, const char *section) { - struct UpdateContext *uc = cls; + struct UpdateContext *uc = cls; + char **ikeys; + char *val; + char *ptr; char *orig_allowed_hosts; char *allowed_hosts; - + char *ACCEPT_FROM_key; + uint16_t ikeys_cnt; + uint16_t key; + + ikeys_cnt = 0; + val = NULL; + if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section, + "TESTING_IGNORE_KEYS")) + { + GNUNET_assert + (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, + "TESTING_IGNORE_KEYS", &val)); + ptr = val; + for (ikeys_cnt = 0; NULL != (ptr = strstr (ptr, ";")); ikeys_cnt++) + ptr++; + if (0 == ikeys_cnt) + GNUNET_break (0); + else + { + ikeys = GNUNET_malloc ((sizeof (char *)) * ikeys_cnt); + ptr = val; + for (key = 0; key < ikeys_cnt; key++) + { + ikeys[key] = ptr; + ptr = strstr (ptr, ";"); + *ptr = '\0'; + ptr++; + } + } + } + if (0 != ikeys_cnt) + { + for (key = 0; key < ikeys_cnt; key++) + { + if (NULL != strstr (ikeys[key], "ADVERTISED_PORT")) + break; + } + if ((key == ikeys_cnt) && + (GNUNET_YES == GNUNET_CONFIGURATION_have_value (uc->cfg, section, + "ADVERTISED_PORT"))) + { + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "PORT", &ptr)) + { + GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, + "ADVERTISED_PORT", ptr); + GNUNET_free (ptr); + } + } + for (key = 0; key < ikeys_cnt; key++) + { + if (NULL != strstr (ikeys[key], "ACCEPT_FROM")) + { + GNUNET_free (ikeys); + GNUNET_free (val); + return; + } + } + GNUNET_free (ikeys); + } + GNUNET_free_non_null (val); + ACCEPT_FROM_key = "ACCEPT_FROM"; + if ((NULL != uc->system->controller) && + (NULL != strstr (uc->system->controller, ":"))) /* IPv6 in use */ + ACCEPT_FROM_key = "ACCEPT_FROM6"; if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "ACCEPT_FROM", + GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, ACCEPT_FROM_key, &orig_allowed_hosts)) { orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;"); @@ -621,16 +757,18 @@ update_config_sections (void *cls, GNUNET_asprintf (&allowed_hosts, "%s%s;", orig_allowed_hosts, uc->system->controller); GNUNET_free (orig_allowed_hosts); - GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, "ACCEPT_FROM", + GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, ACCEPT_FROM_key, allowed_hosts); GNUNET_free (allowed_hosts); } /** - * Create a new configuration using the given configuration - * as a template; ports and paths will be modified to select - * available ports on the local system. If we run + * Create a new configuration using the given configuration as a template; + * ports and paths will be modified to select available ports on the local + * system. The default configuration will be available in PATHS section under + * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS + * section to the temporary directory specific to this configuration. If we run * out of "*port" numbers, return SYSERR. * * This is primarily a helper function used internally @@ -681,7 +819,8 @@ GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system, * changes in port numbers and paths) * @param key_number number of the hostkey to use for the peer * @param id identifier for the daemon, will be set, can be NULL - * @param emsg set to error message (set to NULL on success), can be NULL + * @param emsg set to freshly allocated error message (set to NULL on success), + * can be NULL * @return handle to the peer, NULL on error */ struct GNUNET_TESTING_Peer * @@ -705,7 +844,7 @@ GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system, { GNUNET_asprintf (&emsg_, _("Failed to create configuration for peer (not enough free ports?)\n")); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_); if (NULL != emsg) *emsg = emsg_; else @@ -731,7 +870,7 @@ GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system, GNUNET_asprintf (&emsg_, _("Failed to initialize hostkey for peer %u\n"), (unsigned int) key_number); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_); if (NULL != emsg) *emsg = emsg_; else @@ -756,16 +895,16 @@ GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system, GNUNET_break (0); return NULL; } - if (HOSTKEYFILESIZE != + if (GNUNET_TESTING_HOSTKEYFILESIZE != GNUNET_DISK_file_write (fd, system->hostkeys_data - + (key_number * HOSTKEYFILESIZE), - HOSTKEYFILESIZE)) + + (key_number * GNUNET_TESTING_HOSTKEYFILESIZE), + GNUNET_TESTING_HOSTKEYFILESIZE)) { GNUNET_asprintf (&emsg_, _("Failed to write hostkey file for peer %u: %s\n"), (unsigned int) key_number, STRERROR (errno)); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_); if (NULL != emsg) *emsg = emsg_; else @@ -784,7 +923,7 @@ GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system, config_filename, (unsigned int) key_number, STRERROR (errno)); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_); if (NULL != emsg) *emsg = emsg_; else @@ -794,7 +933,9 @@ GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system, } peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer)); peer->cfgfile = config_filename; /* Free in peer_destroy */ - peer->main_binary = GNUNET_strdup ("gnunet-service-arm"); + peer->main_binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm"); + peer->system = system; + peer->key_number = key_number; return peer; } @@ -806,11 +947,12 @@ GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system, * @param id identifier for the daemon, will be set */ void -GNUNET_TESTING_peer_get_identity (struct GNUNET_TESTING_Peer *peer, +GNUNET_TESTING_peer_get_identity (const struct GNUNET_TESTING_Peer *peer, struct GNUNET_PeerIdentity *id) { - GNUNET_assert (0); // FIXME-SREE. - // *id = peer->id; + GNUNET_CRYPTO_rsa_key_free (GNUNET_TESTING_hostkey_get (peer->system, + peer->key_number, + id)); } @@ -829,7 +971,7 @@ GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer) return GNUNET_SYSERR; } GNUNET_assert (NULL != peer->cfgfile); - peer->main_process = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, + peer->main_process = GNUNET_OS_start_process (GNUNET_YES, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, peer->main_binary, peer->main_binary, "-c", @@ -931,33 +1073,11 @@ struct ServiceContext * Callback to signal service startup */ GNUNET_TESTING_TestMain tm; - - /** - * Closure for the above callback - */ - void *tm_cls; -}; - - -/** - * Structure for holding service data - */ -struct RestartableServiceContext -{ - /** - * The configuration of the peer in which the service is run - */ - const struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * Callback to signal service startup - */ - GNUNET_TESTING_RestartableTestMain tm; - + /** * The peer in which the service is run. */ - const struct GNUNET_TESTING_Peer *peer; + struct GNUNET_TESTING_Peer *peer; /** * Closure for the above callback @@ -978,22 +1098,6 @@ service_run_main (void *cls, { struct ServiceContext *sc = cls; - sc->tm (sc->tm_cls, sc->cfg); -} - - -/** - * Callback to be called when SCHEDULER has been started - * - * @param cls the ServiceContext - * @param tc the TaskContext - */ -static void -service_run_restartable_main (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct RestartableServiceContext *sc = cls; - sc->tm (sc->tm_cls, sc->cfg, sc->peer); } @@ -1030,11 +1134,10 @@ GNUNET_TESTING_service_run (const char *testdir, struct GNUNET_TESTING_System *system; struct GNUNET_TESTING_Peer *peer; struct GNUNET_CONFIGURATION_Handle *cfg; + char *binary; - GNUNET_log_setup (testdir, - "WARNING", - NULL); - system = GNUNET_TESTING_system_create (testdir, "127.0.0.1"); + GNUNET_log_setup (testdir, "WARNING", NULL); + system = GNUNET_TESTING_system_create (testdir, "127.0.0.1", NULL); if (NULL == system) return 1; cfg = GNUNET_CONFIGURATION_create (); @@ -1055,7 +1158,9 @@ GNUNET_TESTING_service_run (const char *testdir, return 1; } GNUNET_free (peer->main_binary); - GNUNET_asprintf (&peer->main_binary, "gnunet-service-%s", service_name); + GNUNET_asprintf (&binary, "gnunet-service-%s", service_name); + peer->main_binary = GNUNET_OS_get_libexec_binary_path (binary); + GNUNET_free (binary); if (GNUNET_OK != GNUNET_TESTING_peer_start (peer)) { GNUNET_TESTING_peer_destroy (peer); @@ -1066,78 +1171,10 @@ GNUNET_TESTING_service_run (const char *testdir, sc.cfg = cfg; sc.tm = tm; sc.tm_cls = tm_cls; - GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */ - if (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)) - { - GNUNET_TESTING_peer_destroy (peer); - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_TESTING_system_destroy (system, GNUNET_YES); - return 1; - } - GNUNET_TESTING_peer_destroy (peer); - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_TESTING_system_destroy (system, GNUNET_YES); - return 0; -} - - - -/** - * See GNUNET_TESTING_service_run. - * The only difference is that we handle the GNUNET_TESTING_Peer to - * the RestartableTestMain, so that the peer can be destroyed and re-created - * to simulate failure in tests. - */ -int -GNUNET_TESTING_service_run_restartable (const char *testdir, - const char *service_name, - const char *cfgfilename, - GNUNET_TESTING_RestartableTestMain tm, - void *tm_cls) -{ - struct RestartableServiceContext sc; - struct GNUNET_TESTING_System *system; - struct GNUNET_TESTING_Peer *peer; - struct GNUNET_CONFIGURATION_Handle *cfg; - - GNUNET_log_setup (testdir, - "WARNING", - NULL); - system = GNUNET_TESTING_system_create (testdir, "127.0.0.1"); - if (NULL == system) - return 1; - cfg = GNUNET_CONFIGURATION_create (); - if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename)) - { - LOG (GNUNET_ERROR_TYPE_ERROR, - _("Failed to load configuration from %s\n"), cfgfilename); - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_TESTING_system_destroy (system, GNUNET_YES); - return 1; - } - peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL); - if (NULL == peer) - { - GNUNET_CONFIGURATION_destroy (cfg); - hostkeys_unload (system); - GNUNET_TESTING_system_destroy (system, GNUNET_YES); - return 1; - } - GNUNET_free (peer->main_binary); - GNUNET_asprintf (&peer->main_binary, "gnunet-service-%s", service_name); - if (GNUNET_OK != GNUNET_TESTING_peer_start (peer)) - { - GNUNET_TESTING_peer_destroy (peer); - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_TESTING_system_destroy (system, GNUNET_YES); - return 1; - } - sc.cfg = cfg; - sc.tm = tm; - sc.tm_cls = tm_cls; sc.peer = peer; - GNUNET_SCHEDULER_run (&service_run_restartable_main, &sc); /* Scheduler loop */ - if (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)) + GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */ + if ((NULL != peer->main_process) && + (GNUNET_OK != GNUNET_TESTING_peer_stop (peer))) { GNUNET_TESTING_peer_destroy (peer); GNUNET_CONFIGURATION_destroy (cfg);