PATCH: sockaddr converters, ipv6

Marcus Meissner marcus at jet.franken.de
Tue Nov 15 15:02:42 CST 2005


Hi,

Implemented sockaddr_in, sockaddr_in6 mapping
between unix and windows sockets.

Slightly complicated because of sockaddr_in6 and
sockaddr_in6_old on Windows. I cross checked with
MSDN.

I hope I did not forget anything this time.

Ciao, Marcus

Changelog:
	Added mapping between unix and windows sockaddr_in6(_old)
	and sockaddr_in. Added address family, socket type mappers.

Index: include/ws2tcpip.h
===================================================================
RCS file: /home/wine/wine/include/ws2tcpip.h,v
retrieving revision 1.5
diff -u -r1.5 ws2tcpip.h
--- include/ws2tcpip.h	21 Sep 2005 09:41:22 -0000	1.5
+++ include/ws2tcpip.h	15 Nov 2005 20:57:09 -0000
@@ -84,19 +84,31 @@
    u_char s6_addr[16];   /* IPv6 address */
 } IN6_ADDR, *PIN6_ADDR, *LPIN6_ADDR;
 
+/* check for sockaddr_in6 / sockaddr_in6_old madness:
+ * http://msdn.microsoft.com/library/en-us/winsock/winsock/sockaddr_2.asp
+ */
 typedef struct WS(sockaddr_in6)
 {
    short   sin6_family;            /* AF_INET6 */
    u_short sin6_port;              /* Transport level port number */
    u_long  sin6_flowinfo;          /* IPv6 flow information */
    struct  WS(in_addr6) sin6_addr; /* IPv6 address */
+   u_long  sin6_scope_id;          /* IPv6 scope id */
 } SOCKADDR_IN6,*PSOCKADDR_IN6, *LPSOCKADDR_IN6;
 
+typedef struct WS(sockaddr_in6_old)
+{
+   short   sin6_family;            /* AF_INET6 */
+   u_short sin6_port;              /* Transport level port number */
+   u_long  sin6_flowinfo;          /* IPv6 flow information */
+   struct  WS(in_addr6) sin6_addr; /* IPv6 address */
+} SOCKADDR_IN6_OLD,*PSOCKADDR_IN6_OLD, *LPSOCKADDR_IN6_OLD;
+
 typedef union sockaddr_gen
 {
    struct WS(sockaddr) Address;
    struct WS(sockaddr_in)  AddressIn;
-   struct WS(sockaddr_in6) AddressIn6;
+   struct WS(sockaddr_in6_old) AddressIn6;
 } WS(sockaddr_gen);
 
 /* Structure to keep interface specific information */
Index: dlls/winsock/socket.c
===================================================================
RCS file: /home/wine/wine/dlls/winsock/socket.c,v
retrieving revision 1.193
diff -u -r1.193 socket.c
--- dlls/winsock/socket.c	5 Nov 2005 10:43:27 -0000	1.193
+++ dlls/winsock/socket.c	15 Nov 2005 20:57:12 -0000
@@ -3,6 +3,7 @@
  * (ftp.microsoft.com:/Advsys/winsock/spec11/WINSOCK.TXT)
  *
  * Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
+ *           (C) 2005 Marcus Meissner
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -285,6 +286,34 @@
     { 0, 0 }
 };
 
+static const int ws_af_map[][2] =
+{
+    MAP_OPTION( AF_INET ),
+    MAP_OPTION( AF_INET6 ),
+#ifdef HAVE_IPX
+    MAP_OPTION( AF_IPX ),
+#endif
+    { 0, 0 }
+};
+
+static const int ws_socktype_map[][2] =
+{
+    MAP_OPTION( SOCK_DGRAM ),
+    MAP_OPTION( SOCK_STREAM ),
+    MAP_OPTION( SOCK_RAW ),
+    { 0, 0 }
+};
+
+static const int ws_proto_map[][2] =
+{
+    MAP_OPTION( IPPROTO_TCP ),
+    MAP_OPTION( IPPROTO_UDP ),
+    MAP_OPTION( IPPROTO_ICMP ),
+    MAP_OPTION( IPPROTO_IGMP ),
+    MAP_OPTION( IPPROTO_RAW ),
+    { 0, 0 }
+};
+
 inline static DWORD NtStatusToWSAError( const DWORD status )
 {
     /* We only need to cover the status codes set by server async request handling */
@@ -658,6 +687,73 @@
   return pfd.revents;
 }
 
+static int
+convert_af_w2u(int windowsaf) {
+    int i;
+
+    for (i=0;ws_af_map[i][0];i++)
+    	if (ws_af_map[i][0] == windowsaf)
+	    return ws_af_map[i][1];
+    FIXME("unhandled Windows address family %d\n", windowsaf);
+    return -1;
+}
+
+static int
+convert_af_u2w(int unixaf) {
+    int i;
+
+    for (i=0;ws_af_map[i][0];i++)
+    	if (ws_af_map[i][1] == unixaf)
+	    return ws_af_map[i][0];
+    FIXME("unhandled UNIX address family %d\n", unixaf);
+    return -1;
+}
+
+static int
+convert_proto_w2u(int windowsproto) {
+    int i;
+
+    for (i=0;ws_proto_map[i][0];i++)
+    	if (ws_proto_map[i][0] == windowsproto)
+	    return ws_proto_map[i][1];
+    FIXME("unhandled Windows socket protocol %d\n", windowsproto);
+    return -1;
+}
+
+static int
+convert_proto_u2w(int unixproto) {
+    int i;
+
+    for (i=0;ws_proto_map[i][0];i++)
+    	if (ws_proto_map[i][1] == unixproto)
+	    return ws_proto_map[i][0];
+    if (unixproto == 0) /* 0 is ok too as wild card */
+   	 return 0;
+    FIXME("unhandled UNIX socket protocol %d\n", unixproto);
+    return -1;
+}
+
+static int
+convert_socktype_w2u(int windowssocktype) {
+    int i;
+
+    for (i=0;ws_socktype_map[i][0];i++)
+    	if (ws_socktype_map[i][0] == windowssocktype)
+	    return ws_socktype_map[i][1];
+    FIXME("unhandled Windows socket type %d\n", windowssocktype);
+    return -1;
+}
+
+static int
+convert_socktype_u2w(int unixsocktype) {
+    int i;
+
+    for (i=0;ws_socktype_map[i][0];i++)
+    	if (ws_socktype_map[i][1] == unixsocktype)
+	    return ws_socktype_map[i][0];
+    FIXME("unhandled UNIX socket type %d\n", unixsocktype);
+    return -1;
+}
 
 /* ----------------------------------- API -----
  *
@@ -803,14 +899,53 @@
             return (const struct sockaddr*)uipx;
         }
 #endif
+    case WS_AF_INET6: {
+        struct sockaddr_in6* uin6;
+        const struct WS_sockaddr_in6* win6 = (struct WS_sockaddr_in6*)wsaddr;
+        const struct WS_sockaddr_in6_old* win6old = (struct WS_sockaddr_in6_old*)wsaddr;
+
+        /* Note: Windows has 2 versions of the sockaddr_in6 struct, one with
+         * scope_id, one without. Check:
+         * http://msdn.microsoft.com/library/en-us/winsock/winsock/sockaddr_2.asp
+         */
+        if (wsaddrlen==sizeof(struct WS_sockaddr_in6_old)) {
+            *uaddrlen=sizeof(struct sockaddr_in6);
+            uin6=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *uaddrlen);
+            uin6->sin6_family   = AF_INET6;
+            uin6->sin6_port     = win6old->sin6_port;
+            uin6->sin6_flowinfo = win6old->sin6_flowinfo;
+            memcpy(&uin6->sin6_addr,&win6old->sin6_addr,16); /* 16 bytes = 128 address bits */
+            return (const struct sockaddr*)uin6;
+        }
+        if (wsaddrlen>=sizeof(struct WS_sockaddr_in6)) {
+            *uaddrlen=sizeof(struct sockaddr_in6);
+            uin6=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *uaddrlen);
+            uin6->sin6_family   = AF_INET6;
+            uin6->sin6_port     = win6->sin6_port;
+            uin6->sin6_flowinfo = win6->sin6_flowinfo;
+            uin6->sin6_scope_id = win6->sin6_scope_id;
+            memcpy(&uin6->sin6_addr,&win6->sin6_addr,16); /* 16 bytes = 128 address bits */
+            return (const struct sockaddr*)uin6;
+        }
+        FIXME("bad size %d for WS_sockaddr_in6\n",wsaddrlen);
+        return NULL;
+    }
+    case WS_AF_INET: {
+        struct sockaddr_in* uin;
+        const struct WS_sockaddr_in* win = (struct WS_sockaddr_in*)wsaddr;
 
-    default:
-        if (wsaddrlen<sizeof(struct WS_sockaddr))
+        if (wsaddrlen<sizeof(struct WS_sockaddr_in))
             return NULL;
-
-        /* No conversion needed, just return the original address */
-        *uaddrlen=wsaddrlen;
-        return (const struct sockaddr*)wsaddr;
+        *uaddrlen=sizeof(struct sockaddr_in);
+        uin = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *uaddrlen);
+        uin->sin_family = AF_INET;
+        uin->sin_port   = win->sin_port;
+        memcpy(&uin->sin_addr,&win->sin_addr,4); /* 4 bytes = 32 address bits */
+        return (const struct sockaddr*)uin;
+    }
+    default:
+        FIXME("Unknown address family %d, return NULL.\n", wsaddr->sa_family);
+        return NULL;
     }
 }
 
@@ -882,16 +1017,47 @@
         }
         break;
 #endif
-
-    default:
-        /* No conversion needed */
-        memcpy(wsaddr,uaddr,*wsaddrlen);
-        if (*wsaddrlen<uaddrlen) {
-            res=-1;
-        } else {
-            *wsaddrlen=uaddrlen;
-            res=0;
+    case AF_INET6: {
+        const struct sockaddr_in6* uin6 = (struct sockaddr_in6*)uaddr;
+        struct WS_sockaddr_in6* win6 = (struct WS_sockaddr_in6*)wsaddr;
+        struct WS_sockaddr_in6_old* win6old = (struct WS_sockaddr_in6_old*)wsaddr;
+
+        if (*wsaddrlen < sizeof(struct WS_sockaddr_in6_old))
+            return -1;
+        if (*wsaddrlen == sizeof(struct WS_sockaddr_in6_old)) {
+            win6old->sin6_family   = WS_AF_INET6;
+            win6old->sin6_port     = uin6->sin6_port;
+            win6old->sin6_flowinfo = uin6->sin6_flowinfo;
+            memcpy(&win6old->sin6_addr,&uin6->sin6_addr,16); /* 16 bytes = 128 address bits */
+            *wsaddrlen = sizeof(struct WS_sockaddr_in6_old);
+            return 0;
         }
+        if (*wsaddrlen >= sizeof(struct WS_sockaddr_in6)) {
+            win6->sin6_family   = WS_AF_INET6;
+            win6->sin6_port     = uin6->sin6_port;
+            win6->sin6_flowinfo = uin6->sin6_flowinfo;
+            memcpy(&win6->sin6_addr,&uin6->sin6_addr,16); /* 16 bytes = 128 address bits */
+            win6->sin6_scope_id = uin6->sin6_scope_id;
+            *wsaddrlen = sizeof(struct WS_sockaddr_in6);
+            return 0;
+        }
+        return 0;
+    }
+    case AF_INET: {
+        struct sockaddr_in* uin = (struct sockaddr_in*)uaddr;
+        struct WS_sockaddr_in* win = (struct WS_sockaddr_in*)wsaddr;
+
+        if (*wsaddrlen < sizeof(struct WS_sockaddr_in))
+            return -1;
+        win->sin_family = WS_AF_INET;
+        win->sin_port   = uin->sin_port;
+        memcpy(&win->sin_addr,&uin->sin_addr,4); /* 4 bytes = 32 address bits */
+        *wsaddrlen = sizeof(struct WS_sockaddr_in6);
+        return 0;
+    }
+    default:
+        FIXME("Unknown address family %d\n", uaddr->sa_family);
+        return -1;
     }
     return res;
 }
@@ -3123,35 +3414,21 @@
       return ret;
     }
 
-    /* check the socket family */
-    switch(af)
-    {
-#ifdef HAVE_IPX
-        case WS_AF_IPX: af = AF_IPX;
-#endif
-        case AF_INET:
-        case AF_UNSPEC:
-            break;
-        default:
-            SetLastError(WSAEAFNOSUPPORT);
-            return INVALID_SOCKET;
+    /* check and convert the socket family */
+    af = convert_af_w2u(af);
+    if (af == -1)
+    {
+      FIXME("Unsupported socket family %d!\n", af);
+      SetLastError(WSAEAFNOSUPPORT);
+      return INVALID_SOCKET;
     }
 
     /* check the socket type */
-    switch(type)
+    type = convert_socktype_w2u(type);
+    if (type == -1)
     {
-        case WS_SOCK_STREAM:
-            type=SOCK_STREAM;
-            break;
-        case WS_SOCK_DGRAM:
-            type=SOCK_DGRAM;
-            break;
-        case WS_SOCK_RAW:
-            type=SOCK_RAW;
-            break;
-        default:
-            SetLastError(WSAESOCKTNOSUPPORT);
-            return INVALID_SOCKET;
+      SetLastError(WSAESOCKTNOSUPPORT);
+      return INVALID_SOCKET;
     }
 
     /* check the protocol type */



More information about the wine-patches mailing list