From 73fa28a84ce456561d3912578121a30bc8263c50 Mon Sep 17 00:00:00 2001 From: Adrian Friedli Date: Wed, 8 Sep 2010 12:50:04 +0200 Subject: [PATCH 4/5] using two separate sockets for IPv4 and IPv6 --- host.c | 53 +++++++++++++++++++++++++++--------- include/enet/enet.h | 11 ++++++- protocol.c | 47 ++++++++++++++++++++++++++++---- unix.c | 74 +++++++++++++++++++++++++++++++++++++------------- 4 files changed, 144 insertions(+), 41 deletions(-) diff --git a/host.c b/host.c index 9ccf894..46e52c9 100644 --- a/host.c +++ b/host.c @@ -7,6 +7,27 @@ #include #include "enet/enet.h" +static ENetSocket +enet_socket_create_bind (const ENetAddress * address, ENetAddressFamily family) +{ + ENetSocket socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM, family); + if (socket == ENET_SOCKET_NULL) + return ENET_SOCKET_NULL; + + if (address != NULL && enet_socket_bind (socket, address, family) < 0) + { + enet_socket_destroy (socket); + return ENET_SOCKET_NULL; + } + + enet_socket_set_option (socket, ENET_SOCKOPT_NONBLOCK, 1); + enet_socket_set_option (socket, ENET_SOCKOPT_BROADCAST, 1); + enet_socket_set_option (socket, ENET_SOCKOPT_RCVBUF, ENET_HOST_RECEIVE_BUFFER_SIZE); + enet_socket_set_option (socket, ENET_SOCKOPT_SNDBUF, ENET_HOST_SEND_BUFFER_SIZE); + + return socket; +} + /** @defgroup host ENet host functions @{ */ @@ -48,23 +69,24 @@ enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelL } memset (host -> peers, 0, peerCount * sizeof (ENetPeer)); - host -> socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM, ENET_IPV6); - if (host -> socket == ENET_SOCKET_NULL || (address != NULL && enet_socket_bind (host -> socket, address, ENET_IPV6) < 0)) - { - if (host -> socket != ENET_SOCKET_NULL) - enet_socket_destroy (host -> socket); + int family = (address == NULL || !memcmp (& address -> host, & ENET_HOST_ANY, sizeof (ENetHostAddress))) ? + ENET_IPV4 | ENET_IPV6 : + enet_get_address_family (address); - enet_free (host -> peers); - enet_free (host); + host -> socket4 = (family & ENET_IPV4) ? + enet_socket_create_bind (address, ENET_IPV4) : + ENET_SOCKET_NULL; + host -> socket6 = (family & ENET_IPV6) ? + enet_socket_create_bind (address, ENET_IPV6) : + ENET_SOCKET_NULL; - return NULL; + if (host -> socket4 == ENET_SOCKET_NULL && host -> socket6 == ENET_SOCKET_NULL) + { + enet_free (host -> peers); + enet_free (host); + return NULL; } - enet_socket_set_option (host -> socket, ENET_SOCKOPT_NONBLOCK, 1); - enet_socket_set_option (host -> socket, ENET_SOCKOPT_BROADCAST, 1); - enet_socket_set_option (host -> socket, ENET_SOCKOPT_RCVBUF, ENET_HOST_RECEIVE_BUFFER_SIZE); - enet_socket_set_option (host -> socket, ENET_SOCKOPT_SNDBUF, ENET_HOST_SEND_BUFFER_SIZE); - if (address != NULL) host -> address = * address; @@ -133,7 +155,10 @@ enet_host_destroy (ENetHost * host) { ENetPeer * currentPeer; - enet_socket_destroy (host -> socket); + if (host -> socket4 != ENET_SOCKET_NULL) + enet_socket_destroy (host -> socket4); + if (host -> socket6 != ENET_SOCKET_NULL) + enet_socket_destroy (host -> socket6); for (currentPeer = host -> peers; currentPeer < & host -> peers [host -> peerCount]; diff --git a/include/enet/enet.h b/include/enet/enet.h index 7f5876f..616fe7f 100644 --- a/include/enet/enet.h +++ b/include/enet/enet.h @@ -335,7 +335,8 @@ typedef enet_uint32 (ENET_CALLBACK * ENetChecksumCallback) (const ENetBuffer * b */ typedef struct _ENetHost { - ENetSocket socket; + ENetSocket socket4; + ENetSocket socket6; ENetAddress address; /**< Internet address of the host */ enet_uint32 incomingBandwidth; /**< downstream bandwidth of the host */ enet_uint32 outgoingBandwidth; /**< upstream bandwidth of the host */ @@ -462,7 +463,7 @@ ENET_API ENetSocket enet_socket_accept (ENetSocket, ENetAddress *, ENetAddressFa ENET_API int enet_socket_connect (ENetSocket, const ENetAddress *, ENetAddressFamily); ENET_API int enet_socket_send (ENetSocket, const ENetAddress *, const ENetBuffer *, size_t, ENetAddressFamily); ENET_API int enet_socket_receive (ENetSocket, ENetAddress *, ENetBuffer *, size_t, ENetAddressFamily); -ENET_API int enet_socket_wait (ENetSocket, enet_uint32 *, enet_uint32); +ENET_API int enet_socket_wait (ENetSocket, ENetSocket, enet_uint32 *, enet_uint32); ENET_API int enet_socket_set_option (ENetSocket, ENetSocketOption, int); ENET_API void enet_socket_destroy (ENetSocket); ENET_API int enet_socketset_select (ENetSocket, ENetSocketSet *, ENetSocketSet *, enet_uint32); @@ -508,6 +509,12 @@ ENET_API int enet_address_get_host (const ENetAddress * address, char * hostName */ ENET_API ENetHostAddress enet_address_map4 (enet_uint32 address); +/** Returns the Address family of an (IPv4-mapped) IPv6 address. + @param address IPv6 address + @returns address family +*/ +ENET_API ENetAddressFamily enet_get_address_family (const ENetAddress * address); + /** @} */ ENET_API ENetPacket * enet_packet_create (const void *, size_t, enet_uint32); diff --git a/protocol.c b/protocol.c index 4c4850a..505c684 100644 --- a/protocol.c +++ b/protocol.c @@ -37,6 +37,14 @@ enet_address_map4 (enet_uint32 address) return addr; } +ENetAddressFamily +enet_get_address_family (const ENetAddress * address) +{ + if (!memcmp(& address->host, & ENET_IPV4MAPPED_PREFIX, ENET_IPV4MAPPED_PREFIX_LEN)) + return ENET_IPV4; + return ENET_IPV6; +} + size_t enet_protocol_command_size (enet_uint8 commandNumber) { @@ -1033,7 +1041,7 @@ commandError: } static int -enet_protocol_receive_incoming_commands (ENetHost * host, ENetEvent * event) +enet_protocol_receive_incoming_commands (ENetHost * host, ENetEvent * event, ENetAddressFamily family) { for (;;) { @@ -1043,11 +1051,11 @@ enet_protocol_receive_incoming_commands (ENetHost * host, ENetEvent * event) buffer.data = host -> packetData [0]; buffer.dataLength = sizeof (host -> packetData [0]); - receivedLength = enet_socket_receive (host -> socket, + receivedLength = enet_socket_receive (family == ENET_IPV4 ? host -> socket4 : host -> socket6, & host -> receivedAddress, & buffer, 1, - ENET_IPV6); + family); if (receivedLength < 0) return -1; @@ -1055,6 +1063,9 @@ enet_protocol_receive_incoming_commands (ENetHost * host, ENetEvent * event) if (receivedLength == 0) return 0; + if (enet_get_address_family (& host -> receivedAddress) != family) + return -1; + host -> receivedData = host -> packetData [0]; host -> receivedDataLength = receivedLength; @@ -1510,7 +1521,15 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch currentPeer -> lastSendTime = host -> serviceTime; - sentLength = enet_socket_send (host -> socket, & currentPeer -> address, host -> buffers, host -> bufferCount, ENET_IPV6); + ENetAddressFamily family = enet_get_address_family (& currentPeer -> address); + ENetSocket socket = family == ENET_IPV4 ? host -> socket4 : host -> socket6; + if (socket == ENET_SOCKET_NULL) + return -1; + sentLength = enet_socket_send (socket, + & currentPeer -> address, + host -> buffers, + host -> bufferCount, + family); enet_protocol_remove_sent_unreliable_commands (currentPeer); @@ -1621,7 +1640,23 @@ enet_host_service (ENetHost * host, ENetEvent * event, enet_uint32 timeout) break; } - switch (enet_protocol_receive_incoming_commands (host, event)) + if (host -> socket4 != ENET_SOCKET_NULL) + switch (enet_protocol_receive_incoming_commands (host, event, ENET_IPV4)) + { + case 1: + return 1; + + case -1: + perror ("Error receiving incoming packets"); + + return -1; + + default: + break; + } + + if (host -> socket6 != ENET_SOCKET_NULL) + switch (enet_protocol_receive_incoming_commands (host, event, ENET_IPV6)) { case 1: return 1; @@ -1673,7 +1708,7 @@ enet_host_service (ENetHost * host, ENetEvent * event, enet_uint32 timeout) waitCondition = ENET_SOCKET_WAIT_RECEIVE; - if (enet_socket_wait (host -> socket, & waitCondition, ENET_TIME_DIFFERENCE (timeout, host -> serviceTime)) != 0) + if (enet_socket_wait (host -> socket4, host -> socket6, & waitCondition, ENET_TIME_DIFFERENCE (timeout, host -> serviceTime)) != 0) return -1; host -> serviceTime = enet_time_get (); diff --git a/unix.c b/unix.c index 475c6e3..751cb6f 100644 --- a/unix.c +++ b/unix.c @@ -116,7 +116,9 @@ static int enet_address_set_sin (struct sockaddr * sin, const ENetAddress * address, ENetAddressFamily family) { memset (sin, 0, enet_sa_size(family)); - if (family == ENET_IPV4) + if (family == ENET_IPV4 && + (enet_get_address_family (address) == ENET_IPV4 || + !memcmp (& address -> host, & ENET_HOST_ANY, sizeof(ENetHostAddress)))) { ((struct sockaddr_in *) sin) -> sin_family = AF_INET; ((struct sockaddr_in *) sin) -> sin_addr = * (struct in_addr *) & address -> host.addr[12]; @@ -218,7 +220,7 @@ enet_socket_create (ENetSocketType type, ENetAddressFamily family) #ifdef IPV6_V6ONLY if (family == ENET_IPV6) { - int value = 0; + int value = 1; setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, & value, sizeof (int)); } #endif // IPV6_V6ONLY @@ -392,22 +394,38 @@ enet_socketset_select (ENetSocket maxSocket, ENetSocketSet * readSet, ENetSocket } int -enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeout) +enet_socket_wait (ENetSocket socket4, ENetSocket socket6, enet_uint32 * condition, enet_uint32 timeout) { #ifdef HAS_POLL - struct pollfd pollSocket; + struct pollfd pollSocket[2]; int pollCount; - - pollSocket.fd = socket; - pollSocket.events = 0; + + pollSocket[0].fd = socket4; + pollSocket[1].fd = socket6; + pollSocket[0].events = 0; + pollSocket[1].events = 0; + //pollSocket[0].revents = 0; + pollSocket[1].revents = 0; + + if (pollSocket[0].fd == ENET_SOCKET_NULL) + { + pollSocket[0].fd = pollSocket[1].fd; + pollSocket[1].fd = ENET_SOCKET_NULL; + } if (* condition & ENET_SOCKET_WAIT_SEND) - pollSocket.events |= POLLOUT; + { + pollSocket[0].events |= POLLOUT; + pollSocket[1].events |= POLLOUT; + } if (* condition & ENET_SOCKET_WAIT_RECEIVE) - pollSocket.events |= POLLIN; + { + pollSocket[0].events |= POLLIN; + pollSocket[1].events |= POLLIN; + } - pollCount = poll (& pollSocket, 1, timeout); + pollCount = poll (pollSocket, pollSocket[1].fd != ENET_SOCKET_NULL ? 2 : 1, timeout); if (pollCount < 0) return -1; @@ -417,10 +435,10 @@ enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeou if (pollCount == 0) return 0; - if (pollSocket.revents & POLLOUT) + if ((pollSocket[0].revents | pollSocket[1].revents) & POLLOUT) * condition |= ENET_SOCKET_WAIT_SEND; - if (pollSocket.revents & POLLIN) + if ((pollSocket[0].revents | pollSocket[1].revents) & POLLIN) * condition |= ENET_SOCKET_WAIT_RECEIVE; return 0; @@ -436,12 +454,28 @@ enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeou FD_ZERO (& writeSet); if (* condition & ENET_SOCKET_WAIT_SEND) - FD_SET (socket, & writeSet); + { + if (socket4 != ENET_SOCKET_NULL) + FD_SET (socket4, & writeSet); + if (socket6 != ENET_SOCKET_NULL) + FD_SET (socket6, & writeSet); + } if (* condition & ENET_SOCKET_WAIT_RECEIVE) - FD_SET (socket, & readSet); + { + if (socket4 != ENET_SOCKET_NULL) + FD_SET (socket4, & readSet); + if (socket6 != ENET_SOCKET_NULL) + FD_SET (socket6, & readSet); + } + + ENetSocket maxSocket = 0; + if (socket4 != ENET_SOCKET_NULL) + maxSocket = socket4; + if (socket6 != ENET_SOCKET_NULL && socket6 > maxSocket) + maxSocket = socket6; - selectCount = select (socket + 1, & readSet, & writeSet, NULL, & timeVal); + selectCount = select (maxSocket + 1, & readSet, & writeSet, NULL, & timeVal); if (selectCount < 0) return -1; @@ -451,11 +485,13 @@ enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeou if (selectCount == 0) return 0; - if (FD_ISSET (socket, & writeSet)) - * condition |= ENET_SOCKET_WAIT_SEND; + if ( (socket4 != ENET_SOCKET_NULL && FD_ISSET (socket4, & writeSet)) || + (socket6 != ENET_SOCKET_NULL && FD_ISSET (socket6, & writeSet)) ) + * condition |= ENET_SOCKET_WAIT_SEND; - if (FD_ISSET (socket, & readSet)) - * condition |= ENET_SOCKET_WAIT_RECEIVE; + if ( (socket4 != ENET_SOCKET_NULL && FD_ISSET (socket4, & readSet)) || + (socket6 != ENET_SOCKET_NULL && FD_ISSET (socket6, & readSet)) ) + * condition |= ENET_SOCKET_WAIT_RECEIVE; return 0; #endif -- 1.7.1