From: Christian Grothoff Date: Wed, 30 Nov 2016 08:51:25 +0000 (+0100) Subject: decided to keep NAT test logic in client library X-Git-Tag: taler-0.2.1~567 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=1466de299c038c5ef738271bd8040276f029e695;p=oweals%2Fgnunet.git decided to keep NAT test logic in client library --- diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h index db479d235..f9b7d3cb8 100644 --- a/src/include/gnunet_protocols.h +++ b/src/include/gnunet_protocols.h @@ -2817,16 +2817,6 @@ extern "C" */ #define GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE 1064 -/** - * Message to ask NAT service to test an address. - */ -#define GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST 1065 - -/** - * Message from NAT service with the address test result. - */ -#define GNUNET_MESSAGE_TYPE_NAT_TEST_RESULT 1066 - /** * Message to ask NAT service to request autoconfiguration. */ diff --git a/src/nat/Makefile.am b/src/nat/Makefile.am index 0ca6dc1d2..d304a57d0 100644 --- a/src/nat/Makefile.am +++ b/src/nat/Makefile.am @@ -86,6 +86,7 @@ libgnunetnat_la_LDFLAGS = \ libgnunetnatnew_la_SOURCES = \ nat_api.c \ nat_api_stun.c nat_stun.h \ + nat_api_test.c \ nat.h libgnunetnatnew_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ diff --git a/src/nat/gnunet-service-nat.c b/src/nat/gnunet-service-nat.c index ffee6374e..1ae0ef2c0 100644 --- a/src/nat/gnunet-service-nat.c +++ b/src/nat/gnunet-service-nat.c @@ -26,6 +26,14 @@ * The purpose of this service is to enable transports to * traverse NAT routers, by providing traversal options and * knowledge about the local network topology. + * + * TODO: + * - call GN_start_gnunet_nat_server_() if possible (i.e. + * when we find we have a non-global IPv4 address) + * - implement handle_test + * - implement autoconfig + * - implmeent UPnPC/PMP-based NAT traversal + * - implement NEW logic for external IP detection */ #include "platform.h" #include @@ -507,32 +515,13 @@ handle_request_connection_reversal (void *cls, GNUNET_SERVICE_client_drop (ch->client); return; } - /* FIXME: actually run the logic! */ + /* FIXME: actually run the logic by + calling 'GN_request_connection_reversal()' */ GNUNET_SERVICE_client_continue (ch->client); } -/** - * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST message from - * client. - * - * @param cls client who sent the message - * @param message the message received - */ -static void -handle_test (void *cls, - const struct GNUNET_NAT_RequestTestMessage *message) -{ - struct ClientHandle *ch = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received REQUEST_TEST message from client\n"); - /* FIXME: actually process test request */ - GNUNET_SERVICE_client_continue (ch->client); -} - - /** * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message * from client. @@ -1071,10 +1060,6 @@ GNUNET_SERVICE_MAIN GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL, struct GNUNET_NAT_RequestConnectionReversalMessage, NULL), - GNUNET_MQ_hd_fixed_size (test, - GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST, - struct GNUNET_NAT_RequestTestMessage, - NULL), GNUNET_MQ_hd_var_size (autoconfig_request, GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG, struct GNUNET_NAT_AutoconfigRequestMessage, diff --git a/src/nat/nat.h b/src/nat/nat.h index a385cede1..6df72c0ab 100644 --- a/src/nat/nat.h +++ b/src/nat/nat.h @@ -233,61 +233,6 @@ struct GNUNET_NAT_AddressChangeNotificationMessage }; -/** - * Client requesting test of network connectivity. - */ -struct GNUNET_NAT_RequestTestMessage -{ - /** - * Header with type #GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST - */ - struct GNUNET_MessageHeader header; - - /** - * Port to bind to, in NBO - */ - uint16_t bind_port GNUNET_PACKED; - - /** - * Port external verifier should try to connect to, in NBO. - */ - uint16_t extern_port GNUNET_PACKED; - - /** - * IPv4 to bind to, in NBO. - */ - struct in_addr bind_ip GNUNET_PACKED; - - /** - * IPv4 external verifier should try to connect to, in NBO. - */ - struct in_addr extern_ip GNUNET_PACKED; - - /** - * IP protocol to use, i.e. IPPROTO_UDP or IPPROTO_TCP. - */ - uint8_t proto; - -}; - - -/** - * Service responding with network connectivity test result. - */ -struct GNUNET_NAT_TestResultMessage -{ - /** - * Header with type #GNUNET_MESSAGE_TYPE_NAT_TEST_RESULT - */ - struct GNUNET_MessageHeader header; - - /** - * An `enum GNUNET_NAT_StatusCode` in NBO. - */ - int32_t status_code GNUNET_PACKED; -}; - - /** * Client requesting automatic configuration. */ diff --git a/src/nat/nat_api.c b/src/nat/nat_api.c index 4c324376b..cab2b657e 100644 --- a/src/nat/nat_api.c +++ b/src/nat/nat_api.c @@ -693,148 +693,6 @@ GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *nh) } -/** - * Handle to a NAT test. - */ -struct GNUNET_NAT_Test -{ - - /** - * Configuration we use. - */ - const struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * Message queue for communicating with the NAT service. - */ - struct GNUNET_MQ_Handle *mq; - - /** - * Function called to report success or failure for - * NAT configuration test. - */ - GNUNET_NAT_TestCallback cb; - - /** - * Closure for @e cb. - */ - void *cb_cls; - -}; - - -/** - * Handle result for a NAT test from the service. - * - * @param cls our `struct GNUNET_NAT_Test *` - * @param rm message with the result of the test - */ -static void -handle_test_result (void *cls, - const struct GNUNET_NAT_TestResultMessage *rm) -{ - struct GNUNET_NAT_Test *tst = cls; - enum GNUNET_NAT_StatusCode sc; - - sc = (enum GNUNET_NAT_StatusCode) ntohl (rm->status_code); - tst->cb (tst->cb_cls, - sc); - GNUNET_NAT_test_stop (tst); -} - - -/** - * Handle queue errors by reporting test failure. - * - * @param cls the `struct GNUNET_NAT_Test *` - * @param error details about the error - */ -static void -tst_error_handler (void *cls, - enum GNUNET_MQ_Error error) -{ - struct GNUNET_NAT_Test *tst = cls; - - tst->cb (tst->cb_cls, - GNUNET_NAT_ERROR_IPC_FAILURE); - GNUNET_NAT_test_stop (tst); -} - - -/** - * Start testing if NAT traversal works using the given configuration - * (IPv4-only). The transport adapters should be down while using - * this function. - * - * @param cfg configuration for the NAT traversal - * @param proto protocol to test, i.e. IPPROTO_TCP or IPPROTO_UDP - * @param bind_ip IPv4 address to bind to - * @param bnd_port port to bind to, 0 to test connection reversal - * @param extern_ip IPv4 address to externally advertise - * @param extern_port externally advertised port to use - * @param report function to call with the result of the test - * @param report_cls closure for @a report - * @return handle to cancel NAT test - */ -struct GNUNET_NAT_Test * -GNUNET_NAT_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg, - uint8_t proto, - struct in_addr bind_ip, - uint16_t bnd_port, - struct in_addr extern_ip, - uint16_t extern_port, - GNUNET_NAT_TestCallback report, - void *report_cls) -{ - struct GNUNET_NAT_Test *tst = GNUNET_new (struct GNUNET_NAT_Test); - struct GNUNET_MQ_MessageHandler handlers[] = { - GNUNET_MQ_hd_fixed_size (test_result, - GNUNET_MESSAGE_TYPE_NAT_TEST_RESULT, - struct GNUNET_NAT_TestResultMessage, - tst), - GNUNET_MQ_handler_end () - }; - struct GNUNET_MQ_Envelope *env; - struct GNUNET_NAT_RequestTestMessage *req; - - tst->cb = report; - tst->cb_cls = report_cls; - tst->mq = GNUNET_CLIENT_connecT (cfg, - "nat", - handlers, - &tst_error_handler, - tst); - if (NULL == tst->mq) - { - GNUNET_break (0); - GNUNET_free (tst); - return NULL; - } - env = GNUNET_MQ_msg (req, - GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST); - req->bind_port = htons (bnd_port); - req->extern_port = htons (extern_port); - req->bind_ip = bind_ip; - req->extern_ip = extern_ip; - req->proto = proto; - GNUNET_MQ_send (tst->mq, - env); - return tst; -} - - -/** - * Stop an active NAT test. - * - * @param tst test to stop. - */ -void -GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst) -{ - GNUNET_MQ_destroy (tst->mq); - GNUNET_free (tst); -} - /** * Handle to auto-configuration in progress. diff --git a/src/nat/nat_api_test.c b/src/nat/nat_api_test.c new file mode 100644 index 000000000..d47c14094 --- /dev/null +++ b/src/nat/nat_api_test.c @@ -0,0 +1,644 @@ +/* + This file is part of GNUnet. + Copyright (C) 2011, 2016 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +/** + * @file nat/nat_api_test.c + * @brief functions to test if the NAT configuration is successful at achieving NAT traversal (with the help of a gnunet-nat-server) + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_nat_lib.h" +#include "nat.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "nat", __VA_ARGS__) + +#define NAT_SERVER_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) + +/** + * Entry we keep for each incoming connection. + */ +struct NatActivity +{ + /** + * This is a doubly-linked list. + */ + struct NatActivity *next; + + /** + * This is a doubly-linked list. + */ + struct NatActivity *prev; + + /** + * Socket of the incoming connection. + */ + struct GNUNET_NETWORK_Handle *sock; + + /** + * Handle of the master context. + */ + struct GNUNET_NAT_Test *h; + + /** + * Task reading from the incoming connection. + */ + struct GNUNET_SCHEDULER_Task *rtask; +}; + + +/** + * Entry we keep for each connection to the gnunet-nat-service. + */ +struct ClientActivity +{ + /** + * This is a doubly-linked list. + */ + struct ClientActivity *next; + + /** + * This is a doubly-linked list. + */ + struct ClientActivity *prev; + + /** + * Socket of the incoming connection. + */ + struct GNUNET_MQ_Handle *mq; + + /** + * Handle to overall NAT test. + */ + struct GNUNET_NAT_Test *h; + +}; + + +/** + * Handle to a NAT test. + */ +struct GNUNET_NAT_Test +{ + + /** + * Configuration used + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Function to call with success report + */ + GNUNET_NAT_TestCallback report; + + /** + * Closure for @e report. + */ + void *report_cls; + + /** + * Handle to NAT traversal in use + */ + struct GNUNET_NAT_Handle *nat; + + /** + * Handle to listen socket, or NULL + */ + struct GNUNET_NETWORK_Handle *lsock; + + /** + * Head of list of nat activities. + */ + struct NatActivity *na_head; + + /** + * Tail of list of nat activities. + */ + struct NatActivity *na_tail; + + /** + * Head of list of client activities. + */ + struct ClientActivity *ca_head; + + /** + * Tail of list of client activities. + */ + struct ClientActivity *ca_tail; + + /** + * Identity of task for the listen socket (if any) + */ + struct GNUNET_SCHEDULER_Task *ltask; + + /** + * Task identifier for the timeout (if any) + */ + struct GNUNET_SCHEDULER_Task *ttask; + + /** + * #GNUNET_YES if we're testing TCP + */ + int is_tcp; + + /** + * Data that should be transmitted or source-port. + */ + uint16_t data; + + /** + * Advertised port to the other peer. + */ + uint16_t adv_port; + + /** + * Status code to be reported to the timeout/status call + */ + enum GNUNET_NAT_StatusCode status; +}; + + +/** + * Function called from #GNUNET_NAT_register whenever someone asks us + * to do connection reversal. + * + * @param cls closure, our `struct GNUNET_NAT_Handle` + * @param addr public IP address of the other peer + * @param addrlen actual lenght of the @a addr + */ +static void +reversal_cb (void *cls, + const struct sockaddr *addr, + socklen_t addrlen) +{ + struct GNUNET_NAT_Test *h = cls; + const struct sockaddr_in *sa; + + if (sizeof (struct sockaddr_in) != addrlen) + return; + sa = (const struct sockaddr_in *) addr; + if (h->data != sa->sin_port) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received connection reversal request for wrong port\n"); + return; /* wrong port */ + } + /* report success */ + h->report (h->report_cls, + GNUNET_NAT_ERROR_SUCCESS); +} + + +/** + * Activity on our incoming socket. Read data from the + * incoming connection. + * + * @param cls the `struct GNUNET_NAT_Test` + */ +static void +do_udp_read (void *cls) +{ + struct GNUNET_NAT_Test *tst = cls; + uint16_t data; + const struct GNUNET_SCHEDULER_TaskContext *tc; + + tc = GNUNET_SCHEDULER_get_task_context (); + tst->ltask = + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, + tst->lsock, + &do_udp_read, + tst); + if ((NULL != tc->write_ready) && + (GNUNET_NETWORK_fdset_isset (tc->read_ready, + tst->lsock)) && + (sizeof (data) == + GNUNET_NETWORK_socket_recv (tst->lsock, + &data, + sizeof (data)))) + { + if (data == tst->data) + tst->report (tst->report_cls, + GNUNET_NAT_ERROR_SUCCESS); + else + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received data mismatches expected value\n"); + } + else + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Failed to receive data from inbound connection\n"); +} + + +/** + * Activity on our incoming socket. Read data from the + * incoming connection. + * + * @param cls the `struct NatActivity` + */ +static void +do_read (void *cls) +{ + struct NatActivity *na = cls; + struct GNUNET_NAT_Test *tst; + uint16_t data; + const struct GNUNET_SCHEDULER_TaskContext *tc; + + tc = GNUNET_SCHEDULER_get_task_context (); + na->rtask = NULL; + tst = na->h; + GNUNET_CONTAINER_DLL_remove (tst->na_head, + tst->na_tail, + na); + if ((NULL != tc->write_ready) && + (GNUNET_NETWORK_fdset_isset (tc->read_ready, + na->sock)) && + (sizeof (data) == + GNUNET_NETWORK_socket_recv (na->sock, + &data, + sizeof (data)))) + { + if (data == tst->data) + tst->report (tst->report_cls, + GNUNET_NAT_ERROR_SUCCESS); + else + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received data does not match expected value\n"); + } + else + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Failed to receive data from inbound connection\n"); + GNUNET_NETWORK_socket_close (na->sock); + GNUNET_free (na); +} + + +/** + * Activity on our listen socket. Accept the + * incoming connection. + * + * @param cls the `struct GNUNET_NAT_Test` + */ +static void +do_accept (void *cls) +{ + struct GNUNET_NAT_Test *tst = cls; + struct GNUNET_NETWORK_Handle *s; + struct NatActivity *wl; + + tst->ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, + tst->lsock, + &do_accept, + tst); + s = GNUNET_NETWORK_socket_accept (tst->lsock, + NULL, + NULL); + if (NULL == s) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO, + "accept"); + return; /* odd error */ + } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Got an inbound connection, waiting for data\n"); + wl = GNUNET_new (struct NatActivity); + wl->sock = s; + wl->h = tst; + wl->rtask = + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, + wl->sock, + &do_read, + wl); + GNUNET_CONTAINER_DLL_insert (tst->na_head, + tst->na_tail, + wl); +} + + +/** + * We got disconnected from the NAT server. Stop + * waiting for a reply. + * + * @param cls the `struct ClientActivity` + * @param error error code + */ +static void +mq_error_handler (void *cls, + enum GNUNET_MQ_Error error) +{ + struct ClientActivity *ca = cls; + struct GNUNET_NAT_Test *tst = ca->h; + + GNUNET_CONTAINER_DLL_remove (tst->ca_head, + tst->ca_tail, + ca); + GNUNET_MQ_destroy (ca->mq); + GNUNET_free (ca); +} + + +/** + * Address-callback, used to send message to gnunet-nat-server. + * + * @param cls closure + * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean + * the previous (now invalid) one + * @param addr either the previous or the new public IP address + * @param addrlen actual length of the @a addr + */ +static void +addr_cb (void *cls, + int add_remove, + const struct sockaddr *addr, + socklen_t addrlen) +{ + struct GNUNET_NAT_Test *h = cls; + struct ClientActivity *ca; + struct GNUNET_MQ_Envelope *env; + struct GNUNET_NAT_TestMessage *msg; + const struct sockaddr_in *sa; + + if (GNUNET_YES != add_remove) + return; + if (addrlen != sizeof (struct sockaddr_in)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "NAT test ignores IPv6 address `%s' returned from NAT library\n", + GNUNET_a2s (addr, + addrlen)); + return; /* ignore IPv6 here */ + } + LOG (GNUNET_ERROR_TYPE_INFO, + "Asking gnunet-nat-server to connect to `%s'\n", + GNUNET_a2s (addr, + addrlen)); + + ca = GNUNET_new (struct ClientActivity); + ca->h = h; + ca->mq = GNUNET_CLIENT_connecT (h->cfg, + "gnunet-nat-server", + NULL, + &mq_error_handler, + ca); + if (NULL == ca->mq) + { + GNUNET_free (ca); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to connect to `gnunet-nat-server'\n")); + return; + } + GNUNET_CONTAINER_DLL_insert (h->ca_head, + h->ca_tail, + ca); + sa = (const struct sockaddr_in *) addr; + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_NAT_TEST); + msg->dst_ipv4 = sa->sin_addr.s_addr; + msg->dport = sa->sin_port; + msg->data = h->data; + msg->is_tcp = htonl ((uint32_t) h->is_tcp); + GNUNET_MQ_send (ca->mq, + env); +} + + +/** + * Timeout task for a nat test. + * Calls the report-callback with a timeout return value + * + * Destroys the nat handle after the callback has been processed. + * + * @param cls handle to the timed out NAT test + */ +static void +do_timeout (void *cls) +{ + struct GNUNET_NAT_Test *nh = cls; + + nh->ttask = NULL; + nh->report (nh->report_cls, + (GNUNET_NAT_ERROR_SUCCESS == nh->status) + ? GNUNET_NAT_ERROR_TIMEOUT + : nh->status); +} + + +/** + * Start testing if NAT traversal works using the + * given configuration (IPv4-only). + * + * ALL failures are reported directly to the report callback + * + * @param cfg configuration for the NAT traversal + * @param is_tcp #GNUNET_YES to test TCP, #GNUNET_NO to test UDP + * @param bnd_port port to bind to, 0 for connection reversal + * @param adv_port externally advertised port to use + * @param timeout delay after which the test should be aborted + * @param report function to call with the result of the test + * @param report_cls closure for @a report + * @return handle to cancel NAT test or NULL. The error is always indicated via the report callback + */ +struct GNUNET_NAT_Test * +GNUNET_NAT_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg, + int is_tcp, + uint16_t bnd_port, + uint16_t adv_port, + struct GNUNET_TIME_Relative timeout, + GNUNET_NAT_TestCallback report, + void *report_cls) +{ + struct GNUNET_NAT_Test *nh; + struct sockaddr_in sa; + const struct sockaddr *addrs[] = { + (const struct sockaddr *) &sa + }; + const socklen_t addrlens[] = { + sizeof (sa) + }; + + memset (&sa, 0, sizeof (sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons (bnd_port); +#if HAVE_SOCKADDR_IN_SIN_LEN + sa.sin_len = sizeof (sa); +#endif + + nh = GNUNET_new (struct GNUNET_NAT_Test); + nh->cfg = cfg; + nh->is_tcp = is_tcp; + nh->data = bnd_port; + nh->adv_port = adv_port; + nh->report = report; + nh->report_cls = report_cls; + nh->status = GNUNET_NAT_ERROR_SUCCESS; + if (0 == bnd_port) + { + nh->nat + = GNUNET_NAT_register (cfg, + is_tcp, + 0, + 0, + NULL, + NULL, + &addr_cb, + &reversal_cb, + nh, + NULL); + } + else + { + nh->lsock = + GNUNET_NETWORK_socket_create (AF_INET, + (is_tcp == + GNUNET_YES) ? SOCK_STREAM : SOCK_DGRAM, + 0); + if ((nh->lsock == NULL) || + (GNUNET_OK != + GNUNET_NETWORK_socket_bind (nh->lsock, + (const struct sockaddr *) &sa, + sizeof (sa)))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to create listen socket bound to `%s' for NAT test: %s\n"), + GNUNET_a2s ((const struct sockaddr *) &sa, + sizeof (sa)), + STRERROR (errno)); + if (NULL != nh->lsock) + { + GNUNET_NETWORK_socket_close (nh->lsock); + nh->lsock = NULL; + } + nh->status = GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR; + nh->ttask = GNUNET_SCHEDULER_add_now (&do_timeout, + nh); + return nh; + } + if (GNUNET_YES == is_tcp) + { + GNUNET_break (GNUNET_OK == + GNUNET_NETWORK_socket_listen (nh->lsock, + 5)); + nh->ltask = + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, + nh->lsock, + &do_accept, + nh); + } + else + { + nh->ltask = + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, + nh->lsock, + &do_udp_read, + nh); + } + LOG (GNUNET_ERROR_TYPE_INFO, + "NAT test listens on port %u (%s)\n", + bnd_port, + (GNUNET_YES == is_tcp) ? "tcp" : "udp"); + nh->nat = GNUNET_NAT_register (cfg, + is_tcp, + adv_port, + 1, + addrs, + addrlens, + &addr_cb, + NULL, + nh, + NULL); + if (NULL == nh->nat) + { + LOG (GNUNET_ERROR_TYPE_INFO, + _("NAT test failed to start NAT library\n")); + if (NULL != nh->ltask) + { + GNUNET_SCHEDULER_cancel (nh->ltask); + nh->ltask = NULL; + } + if (NULL != nh->lsock) + { + GNUNET_NETWORK_socket_close (nh->lsock); + nh->lsock = NULL; + } + nh->status = GNUNET_NAT_ERROR_NAT_REGISTER_FAILED; + nh->ttask = GNUNET_SCHEDULER_add_now (&do_timeout, + nh); + return nh; + } + } + nh->ttask = GNUNET_SCHEDULER_add_delayed (timeout, + &do_timeout, + nh); + return nh; +} + + +/** + * Stop an active NAT test. + * + * @param tst test to stop. + */ +void +GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst) +{ + struct NatActivity *pos; + struct ClientActivity *cpos; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Stopping NAT test\n"); + while (NULL != (cpos = tst->ca_head)) + { + GNUNET_CONTAINER_DLL_remove (tst->ca_head, + tst->ca_tail, + cpos); + GNUNET_MQ_destroy (cpos->mq); + GNUNET_free (cpos); + } + while (NULL != (pos = tst->na_head)) + { + GNUNET_CONTAINER_DLL_remove (tst->na_head, + tst->na_tail, + pos); + GNUNET_SCHEDULER_cancel (pos->rtask); + GNUNET_NETWORK_socket_close (pos->sock); + GNUNET_free (pos); + } + if (NULL != tst->ttask) + { + GNUNET_SCHEDULER_cancel (tst->ttask); + tst->ttask = NULL; + } + if (NULL != tst->ltask) + { + GNUNET_SCHEDULER_cancel (tst->ltask); + tst->ltask = NULL; + } + if (NULL != tst->lsock) + { + GNUNET_NETWORK_socket_close (tst->lsock); + tst->lsock = NULL; + } + if (NULL != tst->nat) + { + GNUNET_NAT_unregister (tst->nat); + tst->nat = NULL; + } + GNUNET_free (tst); +} + +/* end of nat_test.c */