From 93248e1cd75da47980e0d69428747ff6471be1ed Mon Sep 17 00:00:00 2001
From: Adrian Friedli <adi@koalatux.ch>
Date: Thu, 9 Sep 2010 16:02:21 +0200
Subject: [PATCH 5/5] IPv6 for Windows

---
 include/enet/enet.h  |    6 +-
 include/enet/win32.h |    1 +
 win32.c              |  237 ++++++++++++++++++++++++++++++++------------------
 3 files changed, 160 insertions(+), 84 deletions(-)

diff --git a/include/enet/enet.h b/include/enet/enet.h
index 616fe7f..54e3b3b 100644
--- a/include/enet/enet.h
+++ b/include/enet/enet.h
@@ -77,7 +77,11 @@ extern const ENetHostAddress ENET_HOST_BROADCAST;    /**< specifies a IPv4 subne
 typedef struct _ENetAddress
 {
    ENetHostAddress host;
-   enet_uint32 scopeID; //FIXME: this is of different size on Windows
+#ifdef WIN32
+   u_long scopeID;
+#else
+   uint32_t scopeID;
+#endif
    enet_uint16 port;
 } ENetAddress;
 
diff --git a/include/enet/win32.h b/include/enet/win32.h
index 0e1cf0c..9f3f6e5 100644
--- a/include/enet/win32.h
+++ b/include/enet/win32.h
@@ -14,6 +14,7 @@
 
 #include <stdlib.h>
 #include <winsock2.h>
+#include <ws2tcpip.h>
 
 typedef SOCKET ENetSocket;
 
diff --git a/win32.c b/win32.c
index e1fae23..dbbe85a 100644
--- a/win32.c
+++ b/win32.c
@@ -52,77 +52,139 @@ enet_time_set (enet_uint32 newTimeBase)
     timeBase = (enet_uint32) timeGetTime () - newTimeBase;
 }
 
-int
-enet_address_set_host (ENetAddress * address, const char * name)
+static enet_uint16
+enet_af (ENetAddressFamily family)
 {
-    struct hostent * hostEntry;
+    if (family == ENET_IPV4)
+        return AF_INET;
+    if (family == ENET_IPV6)
+        return AF_INET6;
+    return 0;
+}
+
+static socklen_t
+enet_sa_size (ENetAddressFamily family)
+{
+    if (family == ENET_IPV4)
+        return sizeof (SOCKADDR_IN);
+    if (family == ENET_IPV6)
+        return sizeof (SOCKADDR_IN6);
+    return 0;
+}
 
-    hostEntry = gethostbyname (name);
-    if (hostEntry == NULL ||
-        hostEntry -> h_addrtype != AF_INET)
+static ENetAddressFamily
+enet_address_set_address (ENetAddress * address, const SOCKADDR * sin)
+{
+    memset (address, 0, sizeof (ENetAddress));
+    if (sin -> sa_family == AF_INET)
     {
-        unsigned long host = inet_addr (name);
-        if (host == INADDR_NONE)
-            return -1;
-        address -> host = host;
-        return 0;
+        address -> host = enet_address_map4 ((((SOCKADDR_IN *) sin) -> sin_addr.s_addr));
+        //address -> scopeID = 0;
+        address -> port = ENET_NET_TO_HOST_16 (((SOCKADDR_IN *) sin) -> sin_port);
+        return ENET_IPV4;
     }
+    if (sin -> sa_family == AF_INET6)
+    {
+        address -> host = * (ENetHostAddress *) & ((SOCKADDR_IN6 *) sin) -> sin6_addr;
+        address -> scopeID = ((SOCKADDR_IN6 *) sin) -> sin6_scope_id;
+        address -> port = ENET_NET_TO_HOST_16 (((SOCKADDR_IN6 *) sin) -> sin6_port);
+        return ENET_IPV6;
+    }
+    return ENET_NO_ADDRESS_FAMILY;
+}
 
-    address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0];
-
-    return 0;
+static int
+enet_address_set_sin (SOCKADDR * sin, const ENetAddress * address, ENetAddressFamily family)
+{
+    memset (sin, 0, enet_sa_size(family));
+    if (family == ENET_IPV4 &&
+      (enet_get_address_family (address) == ENET_IPV4 ||
+      !memcmp (& address -> host, & ENET_HOST_ANY, sizeof(ENetHostAddress))))
+    {
+        ((SOCKADDR_IN *) sin) -> sin_family = AF_INET;
+        ((SOCKADDR_IN *) sin) -> sin_addr = * (IN_ADDR *) & address -> host.addr[12];
+        ((SOCKADDR_IN *) sin) -> sin_port = ENET_HOST_TO_NET_16 (address -> port);
+        return 0;
+    }
+    else if (family == ENET_IPV6)
+    {
+        ((SOCKADDR_IN6 *) sin) -> sin6_family = AF_INET6;
+        ((SOCKADDR_IN6 *) sin) -> sin6_addr = * (IN6_ADDR *) & address -> host;
+        ((SOCKADDR_IN6 *) sin) -> sin6_scope_id = address -> scopeID;
+        ((SOCKADDR_IN6 *) sin) -> sin6_port = ENET_HOST_TO_NET_16 (address -> port);
+        return 0;
+    }
+    return -1;
 }
 
 int
-enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength)
+enet_address_set_host (ENetAddress * address, const char * name)
 {
-    char * addr = inet_ntoa (* (struct in_addr *) & address -> host);
-    if (addr == NULL)
+    enet_uint16 port = address -> port;
+    ADDRINFO hints;
+    ADDRINFO * result;
+    ADDRINFO * res;
+
+    memset(& hints, 0, sizeof (hints));
+    hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG;
+    hints.ai_family = AF_UNSPEC;
+
+    if ( getaddrinfo(name, NULL, &hints, &result) )
         return -1;
-    strncpy (name, addr, nameLength);
+
+    for (res = result; res != NULL; res = res -> ai_next)
+    {
+        if ( enet_address_set_address(address, res -> ai_addr) != ENET_NO_ADDRESS_FAMILY )
+            break;
+    }
+
+    address -> port = port;
+    freeaddrinfo(result);
+    if (res == NULL) return -1;
+
     return 0;
 }
 
-int
-enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength)
+static int
+enet_address_get_host_x (const ENetAddress * address, char * name, size_t nameLength, int flags)
 {
-    struct in_addr in;
-    struct hostent * hostEntry;
-    
-    in.s_addr = address -> host;
-    
-    hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET);
-    if (hostEntry == NULL)
-      return enet_address_get_host_ip (address, name, nameLength);
+    SOCKADDR_STORAGE sin;
+    enet_address_set_sin((SOCKADDR *) & sin, address, ENET_IPV6);
 
-    strncpy (name, hostEntry -> h_name, nameLength);
+    if ( getnameinfo((SOCKADDR *) & sin, enet_sa_size (ENET_IPV6), name, nameLength, NULL, 0, flags))
+        return -1;
 
     return 0;
 }
 
 int
-enet_socket_bind (ENetSocket socket, const ENetAddress * address)
+enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength)
 {
-    struct sockaddr_in sin;
+    return enet_address_get_host_x(address, name, nameLength, NI_NUMERICHOST);
+}
 
-    memset (& sin, 0, sizeof (struct sockaddr_in));
+int
+enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength)
+{
+    return enet_address_get_host_x(address, name, nameLength, 0);
+}
 
-    sin.sin_family = AF_INET;
+int
+enet_socket_bind (ENetSocket socket, const ENetAddress * address, ENetAddressFamily family)
+{
+    SOCKADDR_STORAGE sin;
 
     if (address != NULL)
     {
-       sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
-       sin.sin_addr.s_addr = address -> host;
+        enet_address_set_sin((SOCKADDR *) & sin, address, family);
     }
     else
     {
-       sin.sin_port = 0;
-       sin.sin_addr.s_addr = INADDR_ANY;
+        ENetAddress address_ = { ENET_HOST_ANY, 0, 0 };
+        enet_address_set_sin((SOCKADDR *) & sin, & address_, family);
     }
 
-    return bind (socket,
-                 (struct sockaddr *) & sin,
-                 sizeof (struct sockaddr_in)) == SOCKET_ERROR ? -1 : 0;
+    return bind (socket, (SOCKADDR *) & sin, enet_sa_size(family)) == SOCKET_ERROR ? -1 : 0;
 }
 
 int
@@ -132,7 +194,7 @@ enet_socket_listen (ENetSocket socket, int backlog)
 }
 
 ENetSocket
-enet_socket_create (ENetSocketType type)
+enet_socket_create (ENetSocketType type, ENetAddressFamily family)
 {
     return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
 }
@@ -173,28 +235,23 @@ enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value)
 }
 
 int
-enet_socket_connect (ENetSocket socket, const ENetAddress * address)
+enet_socket_connect (ENetSocket socket, const ENetAddress * address, ENetAddressFamily family)
 {
-    struct sockaddr_in sin;
-
-    memset (& sin, 0, sizeof (struct sockaddr_in));
+    SOCKADDR_STORAGE sin;
+    enet_address_set_sin((SOCKADDR *) & sin, address, family);
 
-    sin.sin_family = AF_INET;
-    sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
-    sin.sin_addr.s_addr = address -> host;
-
-    return connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in)) == SOCKET_ERROR ? -1 : 0;
+    return connect (socket, (SOCKADDR *) & sin, enet_sa_size(family)) == SOCKET_ERROR ? -1 : 0;
 }
 
 ENetSocket
-enet_socket_accept (ENetSocket socket, ENetAddress * address)
+enet_socket_accept (ENetSocket socket, ENetAddress * address, ENetAddressFamily family)
 {
     SOCKET result;
-    struct sockaddr_in sin;
-    int sinLength = sizeof (struct sockaddr_in);
+    SOCKADDR_STORAGE sin;
+    int sinLength = enet_sa_size (family);
 
     result = accept (socket, 
-                     address != NULL ? (struct sockaddr *) & sin : NULL, 
+                     address != NULL ? (SOCKADDR *) & sin : NULL,
                      address != NULL ? & sinLength : NULL);
 
     if (result == INVALID_SOCKET)
@@ -202,8 +259,7 @@ enet_socket_accept (ENetSocket socket, ENetAddress * address)
 
     if (address != NULL)
     {
-        address -> host = (enet_uint32) sin.sin_addr.s_addr;
-        address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
+        enet_address_set_address(address, (SOCKADDR *) & sin);
     }
 
     return result;
@@ -219,18 +275,15 @@ int
 enet_socket_send (ENetSocket socket,
                   const ENetAddress * address,
                   const ENetBuffer * buffers,
-                  size_t bufferCount)
+                  size_t bufferCount,
+                  ENetAddressFamily family)
 {
-    struct sockaddr_in sin;
+    SOCKADDR_STORAGE sin;
     DWORD sentLength;
 
     if (address != NULL)
     {
-        memset (& sin, 0, sizeof (struct sockaddr_in));
-
-        sin.sin_family = AF_INET;
-        sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
-        sin.sin_addr.s_addr = address -> host;
+        enet_address_set_sin((SOCKADDR *) & sin, address, family);
     }
 
     if (WSASendTo (socket, 
@@ -238,8 +291,8 @@ enet_socket_send (ENetSocket socket,
                    (DWORD) bufferCount,
                    & sentLength,
                    0,
-                   address != NULL ? (struct sockaddr *) & sin : 0,
-                   address != NULL ? sizeof (struct sockaddr_in) : 0,
+                   address != NULL ? (SOCKADDR *) & sin : 0,
+                   address != NULL ? enet_sa_size (family) : 0,
                    NULL,
                    NULL) == SOCKET_ERROR)
     {
@@ -256,19 +309,20 @@ int
 enet_socket_receive (ENetSocket socket,
                      ENetAddress * address,
                      ENetBuffer * buffers,
-                     size_t bufferCount)
+                     size_t bufferCount,
+                     ENetAddressFamily family)
 {
-    INT sinLength = sizeof (struct sockaddr_in);
+    INT sinLength = enet_sa_size (family);
     DWORD flags = 0,
           recvLength;
-    struct sockaddr_in sin;
+    SOCKADDR_STORAGE sin;
 
     if (WSARecvFrom (socket,
                      (LPWSABUF) buffers,
                      (DWORD) bufferCount,
                      & recvLength,
                      & flags,
-                     address != NULL ? (struct sockaddr *) & sin : NULL,
+                     address != NULL ? (SOCKADDR *) & sin : NULL,
                      address != NULL ? & sinLength : NULL,
                      NULL,
                      NULL) == SOCKET_ERROR)
@@ -288,8 +342,7 @@ enet_socket_receive (ENetSocket socket,
 
     if (address != NULL)
     {
-        address -> host = (enet_uint32) sin.sin_addr.s_addr;
-        address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
+        enet_address_set_address(address, (SOCKADDR *) & sin);
     }
 
     return (int) recvLength;
@@ -307,25 +360,41 @@ 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)
 {
     fd_set readSet, writeSet;
     struct timeval timeVal;
     int selectCount;
-    
+
     timeVal.tv_sec = timeout / 1000;
     timeVal.tv_usec = (timeout % 1000) * 1000;
-    
+
     FD_ZERO (& readSet);
     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);
+    }
 
-    selectCount = select (socket + 1, & readSet, & writeSet, NULL, & timeVal);
+    ENetSocket maxSocket = 0;
+    if (socket4 != ENET_SOCKET_NULL)
+        maxSocket = socket4;
+    if (socket6 != ENET_SOCKET_NULL && socket6 > maxSocket)
+        maxSocket = socket6;
+
+    selectCount = select (maxSocket + 1, & readSet, & writeSet, NULL, & timeVal);
 
     if (selectCount < 0)
       return -1;
@@ -335,14 +404,16 @@ 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 (FD_ISSET (socket, & readSet))
-      * condition |= ENET_SOCKET_WAIT_RECEIVE;
+    if ( (socket4 != ENET_SOCKET_NULL && FD_ISSET (socket4, & writeSet)) ||
+        (socket6 != ENET_SOCKET_NULL && FD_ISSET (socket6, & writeSet)) )
+        * condition |= ENET_SOCKET_WAIT_SEND;
+
+    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

