From ed5ede797347e5decdfc56085815dcdf2843609d Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 18 Jul 2010 20:17:35 +0000 Subject: fixing UDP bug --- src/transport/gnunet-service-transport.c | 64 +++- src/transport/plugin_transport_tcp.c | 4 +- src/transport/plugin_transport_udp.c | 438 ++++++++++++++---------- src/transport/test_transport_api.c | 22 +- src/transport/test_transport_api_udp_peer1.conf | 2 +- src/transport/test_transport_api_udp_peer2.conf | 2 +- 6 files changed, 328 insertions(+), 204 deletions(-) diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c index 12db541ac..0d33ac5ca 100644 --- a/src/transport/gnunet-service-transport.c +++ b/src/transport/gnunet-service-transport.c @@ -43,8 +43,6 @@ #define DEBUG_PING_PONG GNUNET_NO -#define SIGN_USELESS GNUNET_NO - #define DEBUG_TRANSPORT_HELLO GNUNET_YES /** @@ -2010,6 +2008,48 @@ remove_session_validations (void *cls, } +/** + * We've been disconnected from the other peer (for some + * connection-oriented transport). Either quickly + * re-establish the connection or signal the disconnect + * to the CORE. + * + * @param p overall plugin context + * @param nl neighbour that was disconnected + */ +static void +try_fast_reconnect (struct TransportPlugin *p, + struct NeighbourList *nl) +{ + /* FIXME-MW: fast reconnect / transport switching not implemented... */ + /* Note: the idea here is to hide problems with transports (or + switching between plugins) from the core to eliminate the need to + re-negotiate session keys and the like; OTOH, we should tell core + quickly (much faster than timeout) `if a connection was lost and + could not be re-established (i.e. other peer went down or is + unable / refuses to communicate); + + So we should consider: + 1) ideally: our own willingness / need to connect + 2) prior failures to connect to this peer (by plugin) + 3) ideally: reaons why other peer terminated (as far as knowable) + + Most importantly, it must be POSSIBLE for another peer to terminate + a connection for a while (without us instantly re-establishing it). + Similarly, if another peer is gone we should quickly notify CORE. + OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport + on the other end), we should reconnect in such a way that BOTH CORE + services never even notice. + Furthermore, the same mechanism (or small variation) could be used + to switch to a better-performing plugin (ATS). + + Finally, this needs to be tested throughly... */ + + /* No reconnect, signal disconnect instead! */ + disconnect_neighbour (nl, GNUNET_NO); +} + + /** * Function that will be called whenever the plugin internally * cleans up a session pointer and hence the service needs to @@ -2037,7 +2077,7 @@ plugin_env_session_end (void *cls, session); nl = find_neighbour (peer); if (nl == NULL) - return; + return; /* was never marked as connected */ rl = nl->plugins; while (rl != NULL) { @@ -2046,7 +2086,7 @@ plugin_env_session_end (void *cls, rl = rl->next; } if (rl == NULL) - return; + return; /* was never marked as connected */ prev = NULL; pos = rl->addresses; while ( (pos != NULL) && @@ -2056,10 +2096,15 @@ plugin_env_session_end (void *cls, pos = pos->next; } if (pos == NULL) - return; + return; /* was never marked as connected */ pos->session = NULL; if (pos->addrlen != 0) - return; + { + if (nl->received_pong != GNUNET_NO) + try_fast_reconnect (p, nl); + return; + } + /* was inbound connection, free 'pos' */ if (prev == NULL) rl->addresses = pos->next; else @@ -2072,13 +2117,16 @@ plugin_env_session_end (void *cls, } GNUNET_free (pos); if (nl->received_pong == GNUNET_NO) - return; /* nothing to do */ + return; /* nothing to do, never connected... */ /* check if we have any validated addresses left */ pos = rl->addresses; while (pos != NULL) { if (pos->validated) - return; + { + try_fast_reconnect (p, nl); + return; + } pos = pos->next; } /* no valid addresses left, signal disconnect! */ diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c index 93ee4c88e..3d12f6909 100644 --- a/src/transport/plugin_transport_tcp.c +++ b/src/transport/plugin_transport_tcp.c @@ -827,8 +827,8 @@ disconnect_session (struct Session *session) else prev->next = session->next; session->plugin->env->session_end (session->plugin->env->cls, - &session->target, - session); + &session->target, + session); /* clean up state */ if (session->transmit_handle != NULL) { diff --git a/src/transport/plugin_transport_udp.c b/src/transport/plugin_transport_udp.c index 582d083dc..5dbb94bcb 100644 --- a/src/transport/plugin_transport_udp.c +++ b/src/transport/plugin_transport_udp.c @@ -328,6 +328,23 @@ struct UDP_NAT_Probes }; +/** + * Information we keep for each of our listen sockets. + */ +struct UDP_Sock_Info +{ + /** + * The network handle + */ + struct GNUNET_NETWORK_Handle *desc; + + /** + * The port we bound to + */ + uint16_t port; +}; + + /** * Encapsulation of all of the state of the plugin. */ @@ -404,6 +421,21 @@ struct Plugin */ const struct GNUNET_DISK_FileHandle *server_stdout_handle; + /** + * Probes in flight + */ + struct UDP_NAT_Probes *probes; + + /** + * socket that we transmit all IPv4 data with + */ + struct UDP_Sock_Info udp_sockv4; + + /** + * socket that we transmit all IPv6 data with + */ + struct UDP_Sock_Info udp_sockv6; + /** * ID of select gnunet-nat-server stdout read task */ @@ -431,31 +463,9 @@ struct Plugin */ pid_t server_pid; - /** - * Probes in flight - */ - struct UDP_NAT_Probes *probes; - }; -struct UDP_Sock_Info -{ - /* The network handle */ - struct GNUNET_NETWORK_Handle *desc; - - /* The port we bound to */ - int port; -}; - -/* *********** globals ************* */ - -/** - * the socket that we transmit all data with - */ -static struct UDP_Sock_Info udp_sock; - - /** * Forward declaration. */ @@ -490,38 +500,35 @@ static int udp_transport_server_stop (void *cls) { struct Plugin *plugin = cls; - int ret; - int ok; - ret = 0; if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (plugin->env->sched, plugin->select_task); plugin->select_task = GNUNET_SCHEDULER_NO_TASK; } - - ok = GNUNET_NETWORK_socket_close (udp_sock.desc); - if (ok == GNUNET_OK) - udp_sock.desc = NULL; - ret += ok; - + if (plugin->udp_sockv4.desc != NULL) + { + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (plugin->udp_sockv4.desc)); + plugin->udp_sockv4.desc = NULL; + } + if (plugin->udp_sockv6.desc != NULL) + { + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (plugin->udp_sockv6.desc)); + plugin->udp_sockv6.desc = NULL; + } if (plugin->behind_nat == GNUNET_YES) { if (0 != PLIBC_KILL (plugin->server_pid, SIGTERM)) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); - } + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); GNUNET_OS_process_wait (plugin->server_pid); } - - if (ret != GNUNET_OK) - return GNUNET_SYSERR; - return ret; + return GNUNET_OK; } struct PeerSession * -find_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *peer) +find_session (struct Plugin *plugin, + const struct GNUNET_PeerIdentity *peer) { struct PeerSession *pos; @@ -559,16 +566,16 @@ find_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *peer) */ static ssize_t udp_real_send (void *cls, - struct GNUNET_NETWORK_Handle *send_handle, - const struct GNUNET_PeerIdentity *target, - const char *msgbuf, - size_t msgbuf_size, - unsigned int priority, - struct GNUNET_TIME_Relative timeout, - const void *addr, - size_t addrlen, - GNUNET_TRANSPORT_TransmitContinuation cont, - void *cont_cls) + struct GNUNET_NETWORK_Handle *send_handle, + const struct GNUNET_PeerIdentity *target, + const char *msgbuf, + size_t msgbuf_size, + unsigned int priority, + struct GNUNET_TIME_Relative timeout, + const void *addr, + size_t addrlen, + GNUNET_TRANSPORT_TransmitContinuation cont, + void *cont_cls) { struct Plugin *plugin = cls; struct UDPMessage *message; @@ -581,11 +588,19 @@ udp_real_send (void *cls, const void *sb; size_t sbs; + if (send_handle == NULL) + { + /* failed to open send socket for AF */ + if (cont != NULL) + cont (cont_cls, target, GNUNET_SYSERR); + return 0; + } if ((addr == NULL) || (addrlen == 0)) { #if DEBUG_UDP - GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _ - ("udp_real_send called without address, returning!\n")); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "udp", + "udp_real_send called without address, returning!\n"); #endif if (cont != NULL) cont (cont_cls, target, GNUNET_SYSERR); @@ -642,7 +657,12 @@ udp_real_send (void *cls, GNUNET_NETWORK_socket_sendto (send_handle, message, ssize, sb, sbs); - + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "UDP transmit %u-byte message to %s (%d: %s)\n", + (unsigned int) ssize, + GNUNET_a2s (sb, sbs), + (int) sent, + (sent < 0) ? STRERROR (errno) : "ok"); if (cont != NULL) { if (sent == GNUNET_SYSERR) @@ -758,7 +778,6 @@ udp_plugin_send (void *cls, } sent = 0; - if ((other_peer_natd == GNUNET_YES) && (plugin->allow_nat == GNUNET_YES)) { peer_session = find_session(plugin, target); @@ -798,7 +817,13 @@ udp_plugin_send (void *cls, { if (peer_session->expecting_welcome == GNUNET_NO) /* We are "connected" */ { - sent = udp_real_send(cls, peer_session->sock, target, msgbuf, msgbuf_size, priority, timeout, peer_session->connect_addr, peer_session->connect_alen, cont, cont_cls); + sent = udp_real_send(cls, + peer_session->sock, + target, + msgbuf, msgbuf_size, + priority, timeout, + peer_session->connect_addr, peer_session->connect_alen, + cont, cont_cls); } else /* Haven't gotten a response from this peer, queue message */ { @@ -816,17 +841,23 @@ udp_plugin_send (void *cls, } else if (other_peer_natd == GNUNET_NO) /* Other peer not behind a NAT, so we can just send the message as is */ { - sent = udp_real_send(cls, udp_sock.desc, target, msgbuf, msgbuf_size, priority, timeout, addr, addrlen, cont, cont_cls); + sent = udp_real_send(cls, + (addrlen == sizeof (struct IPv4UdpAddress)) ? plugin->udp_sockv4.desc : plugin->udp_sockv6.desc, + target, + msgbuf, msgbuf_size, + priority, timeout, addr, addrlen, + cont, cont_cls); } else /* Other peer is NAT'd, but we don't want to play with them (or can't!) */ - return GNUNET_SYSERR; + { + return GNUNET_SYSERR; + } /* When GNUNET_SYSERR is returned from udp_real_send, we will still call * the callback so must not return GNUNET_SYSERR! - * If we do, then transport context get freed twice. */ + * If we did, then transport context would get freed twice. */ if (sent == GNUNET_SYSERR) return 0; - return sent; } @@ -1011,12 +1042,12 @@ static void send_udp_probe_message (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct UDP_NAT_Probes *probe = cls; - struct UDP_NAT_ProbeMessage *message; + struct UDP_NAT_ProbeMessage message; struct Plugin *plugin = probe->plugin; - message = GNUNET_malloc(sizeof(struct UDP_NAT_ProbeMessage)); - message->header.size = htons(sizeof(struct UDP_NAT_ProbeMessage)); - message->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_NAT_PROBE); + memset (&message, 0, sizeof (message)); + message.header.size = htons(sizeof(struct UDP_NAT_ProbeMessage)); + message.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_NAT_PROBE); /* If they gave us a port, use that. If not, try our port. */ if (ntohs(probe->addr.u_port) == 0) probe->addr.u_port = htons(plugin->port); @@ -1025,16 +1056,14 @@ send_udp_probe_message (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "udp", _("Sending a probe to port %d\n"), ntohs(probe->addr.u_port)); #endif - probe->count++; - - udp_real_send(plugin, udp_sock.desc, NULL, - (char *)message, ntohs(message->header.size), 0, - GNUNET_TIME_relative_get_unit(), - &probe->addr, sizeof(probe->addr), - &udp_probe_continuation, probe); - - GNUNET_free(message); + udp_real_send(plugin, + plugin->udp_sockv4.desc, + NULL, + (char *)&message, ntohs(message.header.size), 0, + GNUNET_TIME_relative_get_unit(), + &probe->addr, sizeof(struct IPv4UdpAddress), + &udp_probe_continuation, probe); } @@ -1247,7 +1276,8 @@ udp_demultiplexer(struct Plugin *plugin, struct GNUNET_PeerIdentity *sender, #if DEBUG_UDP GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "udp", - _("Received a probe on listen port %d, sent_from port %d\n"), sockinfo->port, incoming_port); + _("Received a probe on listen port %d, sent_from port %d\n"), + sockinfo->port, incoming_port); #endif udp_real_send(plugin, sockinfo->desc, NULL, @@ -1259,7 +1289,8 @@ udp_demultiplexer(struct Plugin *plugin, struct GNUNET_PeerIdentity *sender, #if DEBUG_UDP GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "udp", - _("Sent PROBE REPLY to port %d on outgoing port %d\n"), incoming_port, sockinfo->port); + _("Sent PROBE REPLY to port %d on outgoing port %d\n"), + incoming_port, sockinfo->port); #endif GNUNET_free(outgoing_probe_reply); break; @@ -1289,8 +1320,11 @@ udp_demultiplexer(struct Plugin *plugin, struct GNUNET_PeerIdentity *sender, outgoing_probe_confirmation = GNUNET_malloc(sizeof(struct UDP_NAT_ProbeMessageConfirmation)); outgoing_probe_confirmation->header.size = htons(sizeof(struct UDP_NAT_ProbeMessageConfirmation)); outgoing_probe_confirmation->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_NAT_PROBE_CONFIRM); - - udp_real_send(plugin, sockinfo->desc, NULL, (char *)outgoing_probe_confirmation, ntohs(outgoing_probe_confirmation->header.size), 0, GNUNET_TIME_relative_get_unit(), sender_addr, fromlen, NULL, NULL); + udp_real_send(plugin, sockinfo->desc, NULL, + (char *)outgoing_probe_confirmation, + ntohs(outgoing_probe_confirmation->header.size), 0, + GNUNET_TIME_relative_get_unit(), + sender_addr, fromlen, NULL, NULL); if (outgoing_probe->task != GNUNET_SCHEDULER_NO_TASK) { @@ -1425,13 +1459,13 @@ udp_demultiplexer(struct Plugin *plugin, struct GNUNET_PeerIdentity *sender, * */ static void -udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +udp_plugin_select (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Plugin *plugin = cls; - char *buf; + char buf[65536]; struct UDPMessage *msg; - struct GNUNET_PeerIdentity *sender; - unsigned int buflen; + struct GNUNET_PeerIdentity sender; socklen_t fromlen; char addr[32]; ssize_t ret; @@ -1446,26 +1480,27 @@ udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) const struct sockaddr_in6 *s6; const void *ca; size_t calen; - + struct UDP_Sock_Info *udp_sock; plugin->select_task = GNUNET_SCHEDULER_NO_TASK; - if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) return; - - buf = NULL; - sender = NULL; - - buflen = GNUNET_NETWORK_socket_recvfrom_amount (udp_sock.desc); - - if (buflen == GNUNET_NO) - return; - - buf = GNUNET_malloc (buflen); + udp_sock = NULL; + if (GNUNET_NETWORK_fdset_isset (tc->read_ready, + plugin->udp_sockv4.desc)) + udp_sock = &plugin->udp_sockv4; + else if (GNUNET_NETWORK_fdset_isset (tc->read_ready, + plugin->udp_sockv6.desc)) + udp_sock = &plugin->udp_sockv6; + if (NULL == udp_sock) + { + GNUNET_break (0); + return; + } fromlen = sizeof (addr); memset (&addr, 0, sizeof(addr)); ret = - GNUNET_NETWORK_socket_recvfrom (udp_sock.desc, buf, buflen, + GNUNET_NETWORK_socket_recvfrom (udp_sock->desc, buf, sizeof (buf), (struct sockaddr *)&addr, &fromlen); if (AF_INET == ((struct sockaddr *)addr)->sa_family) @@ -1492,39 +1527,41 @@ udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) ca = NULL; calen = 0; } - - if (ret <= 0) + if (ret < sizeof (struct UDPMessage)) { - GNUNET_free (buf); + GNUNET_break_op (0); + plugin->select_task = + GNUNET_SCHEDULER_add_select (plugin->env->sched, + GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, + GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs, + NULL, &udp_plugin_select, plugin); return; } msg = (struct UDPMessage *) buf; - if (ntohs (msg->header.size) < sizeof (struct UDPMessage)) { - GNUNET_free (buf); + GNUNET_break_op (0); + plugin->select_task = + GNUNET_SCHEDULER_add_select (plugin->env->sched, + GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, + GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs, + NULL, &udp_plugin_select, plugin); return; } - msgbuf = (char *)&msg[1]; - sender = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity)); - memcpy (sender, &msg->sender, sizeof (struct GNUNET_PeerIdentity)); - + memcpy (&sender, &msg->sender, sizeof (struct GNUNET_PeerIdentity)); offset = 0; count = 0; tsize = ntohs (msg->header.size) - sizeof(struct UDPMessage); - while (offset < tsize) { currhdr = (struct GNUNET_MessageHeader *)&msgbuf[offset]; - udp_demultiplexer(plugin, sender, currhdr, ca, calen, &udp_sock); + udp_demultiplexer(plugin, &sender, currhdr, ca, calen, udp_sock); offset += ntohs(currhdr->size); count++; } - GNUNET_free_non_null (buf); - GNUNET_free_non_null (sender); - - plugin->select_task = GNUNET_SCHEDULER_add_select (plugin->env->sched, GNUNET_SCHEDULER_PRIORITY_DEFAULT, @@ -1535,13 +1572,11 @@ udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) } /** - * Create a slew of UDP sockets. If possible, use IPv6, otherwise - * try IPv4. + * Create a slew of UDP sockets. If possible, use IPv6 and IPv4. * * @param cls closure for server start, should be a struct Plugin * - * * @return number of sockets created or GNUNET_SYSERR on error - */ +*/ static int udp_transport_server_start (void *cls) { @@ -1551,9 +1586,9 @@ udp_transport_server_start (void *cls) struct sockaddr *serverAddr; socklen_t addrlen; int sockets_created; + int tries; sockets_created = 0; - if (plugin->behind_nat == GNUNET_YES) { /* Pipe to read from started processes stdout (on read end) */ @@ -1561,12 +1596,18 @@ udp_transport_server_start (void *cls) if (plugin->server_stdout == NULL) return sockets_created; #if DEBUG_UDP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "udp", - "Starting gnunet-nat-server process cmd: %s %s\n", "gnunet-nat-server", plugin->internal_address); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "udp", + "Starting gnunet-nat-server process cmd: %s %s\n", + "gnunet-nat-server", + plugin->internal_address); #endif /* Start the server process */ - plugin->server_pid = GNUNET_OS_start_process(NULL, plugin->server_stdout, "gnunet-nat-server", "gnunet-nat-server", plugin->internal_address, NULL); + plugin->server_pid = GNUNET_OS_start_process(NULL, + plugin->server_stdout, + "gnunet-nat-server", + "gnunet-nat-server", + plugin->internal_address, NULL); if (plugin->server_pid == GNUNET_SYSERR) { #if DEBUG_UDP @@ -1578,62 +1619,25 @@ udp_transport_server_start (void *cls) } /* Close the write end of the read pipe */ GNUNET_DISK_pipe_close_end(plugin->server_stdout, GNUNET_DISK_PIPE_END_WRITE); - + plugin->server_stdout_handle = GNUNET_DISK_pipe_handle(plugin->server_stdout, GNUNET_DISK_PIPE_END_READ); plugin->server_read_task = - GNUNET_SCHEDULER_add_read_file (plugin->env->sched, - GNUNET_TIME_UNIT_FOREVER_REL, - plugin->server_stdout_handle, &udp_plugin_server_read, plugin); + GNUNET_SCHEDULER_add_read_file (plugin->env->sched, + GNUNET_TIME_UNIT_FOREVER_REL, + plugin->server_stdout_handle, &udp_plugin_server_read, plugin); } - udp_sock.desc = NULL; - - - udp_sock.desc = GNUNET_NETWORK_socket_create (PF_INET, SOCK_DGRAM, 17); - if (NULL == udp_sock.desc) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "udp", "socket"); - return sockets_created; - } - else - { - memset (&serverAddrv4, 0, sizeof (serverAddrv4)); -#if HAVE_SOCKADDR_IN_SIN_LEN - serverAddrv4.sin_len = sizeof (serverAddrv4); -#endif - serverAddrv4.sin_family = AF_INET; - serverAddrv4.sin_addr.s_addr = INADDR_ANY; - serverAddrv4.sin_port = htons (plugin->port); - addrlen = sizeof (serverAddrv4); - serverAddr = (struct sockaddr *) &serverAddrv4; -#if DEBUG_UDP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "udp", - "Binding to port %d\n", ntohs(serverAddrv4.sin_port)); -#endif - while (GNUNET_NETWORK_socket_bind (udp_sock.desc, serverAddr, addrlen) != - GNUNET_OK) - { - serverAddrv4.sin_port = htons (GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_STRONG, 33537) + 32000); /* Find a good, non-root port */ -#if DEBUG_UDP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "udp", - "Binding failed, trying new port %d\n", - ntohs(serverAddrv4.sin_port)); -#endif - } - udp_sock.port = ntohs(serverAddrv4.sin_port); - sockets_created++; - } - - - if ((udp_sock.desc == NULL) && (GNUNET_YES != - GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, "GNUNETD", - "DISABLE-IPV6"))) + if ( (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, "GNUNETD", + "DISABLE-IPV6"))) { - udp_sock.desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_DGRAM, 17); - if (udp_sock.desc != NULL) - { + plugin->udp_sockv6.desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_DGRAM, 17); + if (NULL == plugin->udp_sockv6.desc) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "udp", "socket"); + } + else + { memset (&serverAddrv6, 0, sizeof (serverAddrv6)); #if HAVE_SOCKADDR_IN_SIN_LEN serverAddrv6.sin6_len = sizeof (serverAddrv6); @@ -1643,24 +1647,101 @@ udp_transport_server_start (void *cls) serverAddrv6.sin6_port = htons (plugin->port); addrlen = sizeof (serverAddrv6); serverAddr = (struct sockaddr *) &serverAddrv6; - sockets_created++; - } +#if DEBUG_UDP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "udp", + "Binding to IPv6 port %d\n", + ntohs(serverAddrv6.sin6_port)); +#endif + tries = 0; + while (GNUNET_NETWORK_socket_bind (plugin->udp_sockv6.desc, serverAddr, addrlen) != + GNUNET_OK) + { + serverAddrv6.sin6_port = htons (GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_STRONG, 33537) + 32000); /* Find a good, non-root port */ +#if DEBUG_UDP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "udp", + "IPv6 Binding failed, trying new port %d\n", + ntohs(serverAddrv6.sin6_port)); +#endif + tries++; + if (tries > 10) + { + GNUNET_NETWORK_socket_close (plugin->udp_sockv6.desc); + plugin->udp_sockv6.desc = NULL; + break; + } + } + if (plugin->udp_sockv6.desc != NULL) + { + plugin->udp_sockv6.port = ntohs(serverAddrv6.sin6_port); + sockets_created++; + } + } + } + + plugin->udp_sockv4.desc = GNUNET_NETWORK_socket_create (PF_INET, SOCK_DGRAM, 17); + if (NULL == plugin->udp_sockv4.desc) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "udp", "socket"); + } + else + { + memset (&serverAddrv4, 0, sizeof (serverAddrv4)); +#if HAVE_SOCKADDR_IN_SIN_LEN + serverAddrv4.sin_len = sizeof (serverAddrv4); +#endif + serverAddrv4.sin_family = AF_INET; + serverAddrv4.sin_addr.s_addr = INADDR_ANY; + serverAddrv4.sin_port = htons (plugin->port); + addrlen = sizeof (serverAddrv4); + serverAddr = (struct sockaddr *) &serverAddrv4; +#if DEBUG_UDP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "udp", + "Binding to IPv4 port %d\n", + ntohs(serverAddrv4.sin_port)); +#endif + tries = 0; + while (GNUNET_NETWORK_socket_bind (plugin->udp_sockv4.desc, serverAddr, addrlen) != + GNUNET_OK) + { + serverAddrv4.sin_port = htons (GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_STRONG, 33537) + 32000); /* Find a good, non-root port */ +#if DEBUG_UDP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "udp", + "IPv4 Binding failed, trying new port %d\n", + ntohs(serverAddrv4.sin_port)); +#endif + tries++; + if (tries > 10) + { + GNUNET_NETWORK_socket_close (plugin->udp_sockv4.desc); + plugin->udp_sockv4.desc = NULL; + break; + } + } + if (plugin->udp_sockv4.desc != NULL) + { + plugin->udp_sockv4.port = ntohs(serverAddrv4.sin_port); + sockets_created++; + } } plugin->rs = GNUNET_NETWORK_fdset_create (); - GNUNET_NETWORK_fdset_zero (plugin->rs); - - - GNUNET_NETWORK_fdset_set (plugin->rs, udp_sock.desc); - + if (NULL != plugin->udp_sockv4.desc) + GNUNET_NETWORK_fdset_set (plugin->rs, + plugin->udp_sockv4.desc); + if (NULL != plugin->udp_sockv6.desc) + GNUNET_NETWORK_fdset_set (plugin->rs, + plugin->udp_sockv6.desc); plugin->select_task = GNUNET_SCHEDULER_add_select (plugin->env->sched, GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_SCHEDULER_NO_TASK, GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs, NULL, &udp_plugin_select, plugin); - return sockets_created; } @@ -2167,9 +2248,10 @@ libgnunet_plugin_transport_udp_init (void *cls) } sockets_created = udp_transport_server_start (plugin); - - GNUNET_assert (sockets_created == 1); - + if (sockets_created == 0) + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, + "udp", + _("Failed to open UDP sockets\n")); return api; } diff --git a/src/transport/test_transport_api.c b/src/transport/test_transport_api.c index cd09511ac..52b9282de 100644 --- a/src/transport/test_transport_api.c +++ b/src/transport/test_transport_api.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2009 Christian Grothoff (and other contributing authors) + (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -269,6 +269,7 @@ exchange_hello (void *cls, GNUNET_TRANSPORT_get_hello (p2.th, &exchange_hello_last, &p2); } + static void run (void *cls, struct GNUNET_SCHEDULER_Handle *s, @@ -278,7 +279,6 @@ run (void *cls, GNUNET_assert (ok == 1); OKPP; sched = s; - die_task = GNUNET_SCHEDULER_add_delayed (sched, TIMEOUT, &end_badly, NULL); @@ -318,8 +318,7 @@ run (void *cls, static int check () { - - char *const argv[] = { "test-transport-api", + static char *const argv[] = { "test-transport-api", "-c", "test_transport_api_data.conf", #if VERBOSE @@ -327,15 +326,13 @@ check () #endif NULL }; + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; #if WRITECONFIG setTransportOptions("test_transport_api_data.conf"); #endif - - struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_OPTION_END - }; - ok = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-transport-api", "nohelp", @@ -374,13 +371,10 @@ get_path_from_PATH () pos = end + 1; } sprintf (buf, "%s/%s", pos, "gnunet-nat-server"); + GNUNET_free (path); if (GNUNET_DISK_file_test (buf) == GNUNET_YES) - { - GNUNET_free (path); - return buf; - } + return buf; GNUNET_free (buf); - GNUNET_free (path); return NULL; } diff --git a/src/transport/test_transport_api_udp_peer1.conf b/src/transport/test_transport_api_udp_peer1.conf index 49efbff63..53e11f4c2 100644 --- a/src/transport/test_transport_api_udp_peer1.conf +++ b/src/transport/test_transport_api_udp_peer1.conf @@ -34,7 +34,7 @@ AUTOSTART = NO [transport] PLUGINS = udp -DEBUG = NO +DEBUG = YES ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; NEIGHBOUR_LIMIT = 50 diff --git a/src/transport/test_transport_api_udp_peer2.conf b/src/transport/test_transport_api_udp_peer2.conf index 284f09b21..764674ba1 100644 --- a/src/transport/test_transport_api_udp_peer2.conf +++ b/src/transport/test_transport_api_udp_peer2.conf @@ -31,7 +31,7 @@ MINIMUM-FRIENDS = 0 [transport] PLUGINS = udp -DEBUG = NO +DEBUG = YES PREFIX = ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; -- cgit v1.2.3