[PATCH 2/5] ws2_32: Move getaddrinfo() support to a new Unix library.

Zebediah Figura zfigura at codeweavers.com
Tue Aug 3 23:53:33 CDT 2021


Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
 dlls/ws2_32/Makefile.in      |   3 +-
 dlls/ws2_32/protocol.c       | 316 ++----------------
 dlls/ws2_32/socket.c         | 150 +--------
 dlls/ws2_32/tests/protocol.c |   4 +-
 dlls/ws2_32/unixlib.c        | 618 +++++++++++++++++++++++++++++++++++
 dlls/ws2_32/ws2_32_private.h |  12 +-
 6 files changed, 673 insertions(+), 430 deletions(-)
 create mode 100644 dlls/ws2_32/unixlib.c

diff --git a/dlls/ws2_32/Makefile.in b/dlls/ws2_32/Makefile.in
index 6312b20739d..77983bba66f 100644
--- a/dlls/ws2_32/Makefile.in
+++ b/dlls/ws2_32/Makefile.in
@@ -7,6 +7,7 @@ EXTRALIBS = $(POLL_LIBS)
 C_SRCS = \
 	async.c \
 	protocol.c \
-	socket.c
+	socket.c \
+	unixlib.c
 
 RC_SRCS = version.rc
diff --git a/dlls/ws2_32/protocol.c b/dlls/ws2_32/protocol.c
index 944f26912e6..7b6e68555b0 100644
--- a/dlls/ws2_32/protocol.c
+++ b/dlls/ws2_32/protocol.c
@@ -33,21 +33,6 @@ DECLARE_CRITICAL_SECTION(csWSgetXXXbyYYY);
 
 #define MAP_OPTION(opt) { WS_##opt, opt }
 
-static const int ws_aiflag_map[][2] =
-{
-    MAP_OPTION( AI_PASSIVE ),
-    MAP_OPTION( AI_CANONNAME ),
-    MAP_OPTION( AI_NUMERICHOST ),
-#ifdef AI_NUMERICSERV
-    MAP_OPTION( AI_NUMERICSERV ),
-#endif
-#ifdef AI_V4MAPPED
-    MAP_OPTION( AI_V4MAPPED ),
-#endif
-    MAP_OPTION( AI_ALL ),
-    MAP_OPTION( AI_ADDRCONFIG ),
-};
-
 static const int ws_eai_map[][2] =
 {
     MAP_OPTION( EAI_AGAIN ),
@@ -82,21 +67,6 @@ static const int ws_af_map[][2] =
     {FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO},
 };
 
-static const int ws_proto_map[][2] =
-{
-    MAP_OPTION( IPPROTO_IP ),
-    MAP_OPTION( IPPROTO_TCP ),
-    MAP_OPTION( IPPROTO_UDP ),
-    MAP_OPTION( IPPROTO_IPV6 ),
-    MAP_OPTION( IPPROTO_ICMP ),
-    MAP_OPTION( IPPROTO_IGMP ),
-    MAP_OPTION( IPPROTO_RAW ),
-    {WS_IPPROTO_IPV4, IPPROTO_IPIP},
-    {FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO},
-};
-
-#define IS_IPX_PROTO(X) ((X) >= WS_NSPROTO_IPX && (X) <= WS_NSPROTO_IPX + 255)
-
 static int convert_af_w2u( int family )
 {
     unsigned int i;
@@ -123,78 +93,6 @@ static int convert_af_u2w( int family )
     return -1;
 }
 
-static int convert_proto_w2u( int protocol )
-{
-    unsigned int i;
-
-    for (i = 0; i < ARRAY_SIZE(ws_proto_map); i++)
-    {
-        if (ws_proto_map[i][0] == protocol)
-            return ws_proto_map[i][1];
-    }
-
-    if (IS_IPX_PROTO(protocol))
-      return protocol;
-
-    FIXME( "unhandled Windows socket protocol %d\n", protocol );
-    return -1;
-}
-
-static int convert_proto_u2w( int protocol )
-{
-    unsigned int i;
-
-    for (i = 0; i < ARRAY_SIZE(ws_proto_map); i++)
-    {
-        if (ws_proto_map[i][1] == protocol)
-            return ws_proto_map[i][0];
-    }
-
-    /* if value is inside IPX range just return it - the kernel simply
-     * echoes the value used in the socket() function */
-    if (IS_IPX_PROTO(protocol))
-        return protocol;
-
-    FIXME("unhandled UNIX socket protocol %d\n", protocol);
-    return -1;
-}
-
-static int convert_aiflag_w2u( int winflags )
-{
-    unsigned int i;
-    int unixflags = 0;
-
-    for (i = 0; i < ARRAY_SIZE(ws_aiflag_map); i++)
-    {
-        if (ws_aiflag_map[i][0] & winflags)
-        {
-            unixflags |= ws_aiflag_map[i][1];
-            winflags &= ~ws_aiflag_map[i][0];
-        }
-    }
-    if (winflags)
-        FIXME( "Unhandled windows AI_xxx flags 0x%x\n", winflags );
-    return unixflags;
-}
-
-static int convert_aiflag_u2w( int unixflags )
-{
-    unsigned int i;
-    int winflags = 0;
-
-    for (i = 0; i < ARRAY_SIZE(ws_aiflag_map); i++)
-    {
-        if (ws_aiflag_map[i][1] & unixflags)
-        {
-            winflags |= ws_aiflag_map[i][0];
-            unixflags &= ~ws_aiflag_map[i][1];
-        }
-    }
-    if (unixflags)
-        WARN( "Unhandled UNIX AI_xxx flags 0x%x\n", unixflags );
-    return winflags;
-}
-
 int convert_eai_u2w( int unixret )
 {
     int i;
@@ -232,62 +130,37 @@ static char *get_fqdn(void)
     return ret;
 }
 
-static BOOL addrinfo_in_list( const struct WS_addrinfo *list, const struct WS_addrinfo *ai )
-{
-    const struct WS_addrinfo *cursor = list;
-    while (cursor)
-    {
-        if (ai->ai_flags == cursor->ai_flags &&
-            ai->ai_family == cursor->ai_family &&
-            ai->ai_socktype == cursor->ai_socktype &&
-            ai->ai_protocol == cursor->ai_protocol &&
-            ai->ai_addrlen == cursor->ai_addrlen &&
-            !memcmp(ai->ai_addr, cursor->ai_addr, ai->ai_addrlen) &&
-            ((ai->ai_canonname && cursor->ai_canonname && !strcmp(ai->ai_canonname, cursor->ai_canonname))
-            || (!ai->ai_canonname && !cursor->ai_canonname)))
-        {
-            return TRUE;
-        }
-        cursor = cursor->ai_next;
-    }
-    return FALSE;
-}
 
 
 /***********************************************************************
  *      getaddrinfo   (ws2_32.@)
  */
-int WINAPI WS_getaddrinfo( const char *nodename, const char *servname,
-                           const struct WS_addrinfo *hints, struct WS_addrinfo **res )
+int WINAPI WS_getaddrinfo( const char *node, const char *service,
+                           const struct WS_addrinfo *hints, struct WS_addrinfo **info )
 {
-#ifdef HAVE_GETADDRINFO
-    struct addrinfo *unixaires = NULL;
-    int result;
-    struct addrinfo unixhints, *punixhints = NULL;
     char *nodev6 = NULL, *fqdn = NULL;
-    const char *node;
+    int ret;
 
-    *res = NULL;
-    if (!nodename && !servname)
+    TRACE( "node %s, service %s, hints %p\n", debugstr_a(node), debugstr_a(service), hints );
+
+    *info = NULL;
+
+    if (!node && !service)
     {
-        SetLastError(WSAHOST_NOT_FOUND);
+        SetLastError( WSAHOST_NOT_FOUND );
         return WSAHOST_NOT_FOUND;
     }
 
-    if (!nodename)
-        node = NULL;
-    else if (!nodename[0])
-    {
-        if (!(fqdn = get_fqdn())) return WSA_NOT_ENOUGH_MEMORY;
-        node = fqdn;
-    }
-    else
+    if (node)
     {
-        node = nodename;
-
-        /* Check for [ipv6] or [ipv6]:portnumber, which are supported by Windows */
-        if (!hints || hints->ai_family == WS_AF_UNSPEC || hints->ai_family == WS_AF_INET6)
+        if (!node[0])
         {
+            if (!(fqdn = get_fqdn())) return WSA_NOT_ENOUGH_MEMORY;
+            node = fqdn;
+        }
+        else if (!hints || hints->ai_family == WS_AF_UNSPEC || hints->ai_family == WS_AF_INET6)
+        {
+            /* [ipv6] or [ipv6]:portnumber are supported by Windows */
             char *close_bracket;
 
             if (node[0] == '[' && (close_bracket = strchr(node + 1, ']')))
@@ -300,50 +173,9 @@ int WINAPI WS_getaddrinfo( const char *nodename, const char *servname,
         }
     }
 
-    /* servname tweak required by OSX and BSD kernels */
-    if (servname && !servname[0]) servname = "0";
-
-    if (hints)
-    {
-        punixhints = &unixhints;
-
-        memset( &unixhints, 0, sizeof(unixhints) );
-        punixhints->ai_flags = convert_aiflag_w2u( hints->ai_flags );
-
-        /* zero is a wildcard, no need to convert */
-        if (hints->ai_family)
-            punixhints->ai_family = convert_af_w2u( hints->ai_family );
-        if (hints->ai_socktype)
-            punixhints->ai_socktype = convert_socktype_w2u( hints->ai_socktype );
-        if (hints->ai_protocol)
-            punixhints->ai_protocol = max( convert_proto_w2u( hints->ai_protocol ), 0 );
-
-        if (punixhints->ai_socktype < 0)
-        {
-            SetLastError( WSAESOCKTNOSUPPORT );
-            HeapFree( GetProcessHeap(), 0, fqdn );
-            HeapFree( GetProcessHeap(), 0, nodev6 );
-            return -1;
-        }
-
-        /* windows allows invalid combinations of socket type and protocol, unix does not.
-         * fix the parameters here to make getaddrinfo call always work */
-        if (punixhints->ai_protocol == IPPROTO_TCP
-                && punixhints->ai_socktype != SOCK_STREAM
-                && punixhints->ai_socktype != SOCK_SEQPACKET)
-            punixhints->ai_socktype = 0;
-        else if (punixhints->ai_protocol == IPPROTO_UDP && punixhints->ai_socktype != SOCK_DGRAM)
-            punixhints->ai_socktype = 0;
-        else if (IS_IPX_PROTO(punixhints->ai_protocol) && punixhints->ai_socktype != SOCK_DGRAM)
-            punixhints->ai_socktype = 0;
-        else if (punixhints->ai_protocol == IPPROTO_IPV6)
-            punixhints->ai_protocol = 0;
-    }
-
-    /* getaddrinfo(3) is thread safe, no need to wrap in CS */
-    result = getaddrinfo( node, servname, punixhints, &unixaires );
+    ret = unix_funcs->getaddrinfo( node, service, hints, info );
 
-    if (result && (!hints || !(hints->ai_flags & WS_AI_NUMERICHOST)) && node)
+    if (ret && (!hints || !(hints->ai_flags & WS_AI_NUMERICHOST)) && node)
     {
         if (!fqdn && !(fqdn = get_fqdn()))
         {
@@ -356,115 +188,33 @@ int WINAPI WS_getaddrinfo( const char *nodename, const char *servname,
              * by sending a NULL host and avoid sending a NULL servname too because that
              * is invalid */
             ERR_(winediag)( "Failed to resolve your host name IP\n" );
-            result = getaddrinfo( NULL, servname ? servname : "0", punixhints, &unixaires );
-            if (!result && punixhints && (punixhints->ai_flags & AI_CANONNAME) && unixaires && !unixaires->ai_canonname)
+            ret = unix_funcs->getaddrinfo( NULL, service, hints, info );
+            if (!ret && hints && (hints->ai_flags & WS_AI_CANONNAME) && *info && !(*info)->ai_canonname)
             {
-                freeaddrinfo( unixaires );
-                result = EAI_NONAME;
+                WS_freeaddrinfo( *info );
+                *info = NULL;
+                return EAI_NONAME;
             }
         }
     }
-    TRACE( "%s, %s %p -> %p %d\n", debugstr_a(nodename), debugstr_a(servname), hints, res, result );
+
     HeapFree( GetProcessHeap(), 0, fqdn );
     HeapFree( GetProcessHeap(), 0, nodev6 );
 
-    if (!result)
+    if (!ret && TRACE_ON(winsock))
     {
-        struct addrinfo *xuai = unixaires;
-        struct WS_addrinfo **xai = res;
-
-        *xai = NULL;
-        while (xuai)
-        {
-            struct WS_addrinfo *ai = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct WS_addrinfo) );
-            SIZE_T len;
-
-            if (!ai)
-                goto outofmem;
-
-            ai->ai_flags    = convert_aiflag_u2w( xuai->ai_flags );
-            ai->ai_family   = convert_af_u2w( xuai->ai_family );
-            /* copy whatever was sent in the hints */
-            if (hints)
-            {
-                ai->ai_socktype = hints->ai_socktype;
-                ai->ai_protocol = hints->ai_protocol;
-            }
-            else
-            {
-                ai->ai_socktype = convert_socktype_u2w( xuai->ai_socktype );
-                ai->ai_protocol = convert_proto_u2w( xuai->ai_protocol );
-            }
-            if (xuai->ai_canonname)
-            {
-                TRACE( "canon name - %s\n", debugstr_a(xuai->ai_canonname) );
-                ai->ai_canonname = HeapAlloc( GetProcessHeap(), 0, strlen( xuai->ai_canonname ) + 1 );
-                if (!ai->ai_canonname)
-                    goto outofmem;
-                strcpy( ai->ai_canonname, xuai->ai_canonname );
-            }
-            len = xuai->ai_addrlen;
-            ai->ai_addr = HeapAlloc( GetProcessHeap(), 0, len );
-            if (!ai->ai_addr)
-                goto outofmem;
-            ai->ai_addrlen = len;
-            do
-            {
-                int winlen = ai->ai_addrlen;
-
-                if (!ws_sockaddr_u2ws( xuai->ai_addr, ai->ai_addr, &winlen ))
-                {
-                    ai->ai_addrlen = winlen;
-                    break;
-                }
-                len *= 2;
-                ai->ai_addr = HeapReAlloc( GetProcessHeap(), 0, ai->ai_addr, len );
-                if (!ai->ai_addr)
-                    goto outofmem;
-                ai->ai_addrlen = len;
-            } while (1);
-
-            if (addrinfo_in_list( *res, ai ))
-            {
-                HeapFree( GetProcessHeap(), 0, ai->ai_canonname );
-                HeapFree( GetProcessHeap(), 0, ai->ai_addr );
-                HeapFree( GetProcessHeap(), 0, ai );
-            }
-            else
-            {
-                *xai = ai;
-                xai = &ai->ai_next;
-            }
-            xuai = xuai->ai_next;
-        }
-        freeaddrinfo( unixaires );
+        struct WS_addrinfo *ai;
 
-        if (TRACE_ON(winsock))
+        for (ai = *info; ai != NULL; ai = ai->ai_next)
         {
-            struct WS_addrinfo *ai = *res;
-            while (ai)
-            {
-                TRACE( "=> %p, flags %#x, family %d, type %d, protocol %d, len %ld, name %s, addr %s\n",
-                       ai, ai->ai_flags, ai->ai_family, ai->ai_socktype, ai->ai_protocol, ai->ai_addrlen,
-                       ai->ai_canonname, debugstr_sockaddr(ai->ai_addr) );
-                ai = ai->ai_next;
-            }
+            TRACE( "=> %p, flags %#x, family %d, type %d, protocol %d, len %ld, name %s, addr %s\n",
+                   ai, ai->ai_flags, ai->ai_family, ai->ai_socktype, ai->ai_protocol, ai->ai_addrlen,
+                   ai->ai_canonname, debugstr_sockaddr(ai->ai_addr) );
         }
     }
-    else
-        result = convert_eai_u2w( result );
-
-    SetLastError( result );
-    return result;
 
-outofmem:
-    if (*res) WS_freeaddrinfo( *res );
-    if (unixaires) freeaddrinfo( unixaires );
-    return WSA_NOT_ENOUGH_MEMORY;
-#else
-    FIXME( "getaddrinfo() failed, not found during build time.\n" );
-    return EAI_FAIL;
-#endif
+    SetLastError( ret );
+    return ret;
 }
 
 
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 2bcd15463f8..b52e0d37e90 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -41,6 +41,8 @@
 WINE_DEFAULT_DEBUG_CHANNEL(winsock);
 WINE_DECLARE_DEBUG_CHANNEL(winediag);
 
+const struct unix_funcs *unix_funcs = NULL;
+
 static const WSAPROTOCOL_INFOW supported_protocols[] =
 {
     {
@@ -426,14 +428,6 @@ static int ws_protocol_info(SOCKET s, int unicode, WSAPROTOCOL_INFOW *buffer, in
 
 #define MAP_OPTION(opt) { WS_##opt, opt }
 
-static const int ws_socktype_map[][2] =
-{
-    MAP_OPTION( SOCK_DGRAM ),
-    MAP_OPTION( SOCK_STREAM ),
-    MAP_OPTION( SOCK_RAW ),
-    {FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO},
-};
-
 UINT sock_get_error( int err )
 {
 	switch(err)
@@ -626,38 +620,20 @@ static HANDLE get_sync_event(void)
     return data->sync_event;
 }
 
-/***********************************************************************
- *		DllMain (WS2_32.init)
- */
+
 BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved )
 {
-    if (reason == DLL_THREAD_DETACH)
+    switch (reason)
+    {
+    case DLL_PROCESS_ATTACH:
+        return !__wine_init_unix_lib( instance, reason, NULL, &unix_funcs );
+
+    case DLL_THREAD_DETACH:
         free_per_thread_data();
+    }
     return TRUE;
 }
 
-int
-convert_socktype_w2u(int windowssocktype) {
-    unsigned int i;
-
-    for (i = 0; i < ARRAY_SIZE(ws_socktype_map); i++)
-    	if (ws_socktype_map[i][0] == windowssocktype)
-	    return ws_socktype_map[i][1];
-    FIXME("unhandled Windows socket type %d\n", windowssocktype);
-    return -1;
-}
-
-int
-convert_socktype_u2w(int unixsocktype) {
-    unsigned int i;
-
-    for (i = 0; i < ARRAY_SIZE(ws_socktype_map); i++)
-    	if (ws_socktype_map[i][1] == unixsocktype)
-	    return ws_socktype_map[i][0];
-    FIXME("unhandled UNIX socket type %d\n", unixsocktype);
-    return -1;
-}
-
 
 /***********************************************************************
  *      WSAStartup		(WS2_32.115)
@@ -858,112 +834,6 @@ unsigned int ws_sockaddr_ws2u( const struct WS_sockaddr *wsaddr, int wsaddrlen,
     return uaddrlen;
 }
 
-/* Returns 0 if successful, -1 if the buffer is too small */
-int ws_sockaddr_u2ws(const struct sockaddr *uaddr, struct WS_sockaddr *wsaddr, int *wsaddrlen)
-{
-    int res;
-
-    switch(uaddr->sa_family)
-    {
-#ifdef HAS_IPX
-    case AF_IPX:
-        {
-            const struct sockaddr_ipx* uipx=(const struct sockaddr_ipx*)uaddr;
-            struct WS_sockaddr_ipx* wsipx=(struct WS_sockaddr_ipx*)wsaddr;
-
-            res=-1;
-            switch (*wsaddrlen) /* how much can we copy? */
-            {
-            default:
-                res=0; /* enough */
-                *wsaddrlen = sizeof(*wsipx);
-                wsipx->sa_socket=uipx->sipx_port;
-                /* fall through */
-            case 13:
-            case 12:
-                memcpy(wsipx->sa_nodenum,uipx->sipx_node,sizeof(wsipx->sa_nodenum));
-                /* fall through */
-            case 11:
-            case 10:
-            case 9:
-            case 8:
-            case 7:
-            case 6:
-                memcpy(wsipx->sa_netnum,&uipx->sipx_network,sizeof(wsipx->sa_netnum));
-                /* fall through */
-            case 5:
-            case 4:
-            case 3:
-            case 2:
-                wsipx->sa_family=WS_AF_IPX;
-                /* fall through */
-            case 1:
-            case 0:
-                /* way too small */
-                break;
-            }
-        }
-        break;
-#endif
-#ifdef HAS_IRDA
-    case AF_IRDA: {
-        const struct sockaddr_irda *uin = (const struct sockaddr_irda *)uaddr;
-        SOCKADDR_IRDA *win = (SOCKADDR_IRDA *)wsaddr;
-
-        if (*wsaddrlen < sizeof(SOCKADDR_IRDA))
-            return -1;
-        win->irdaAddressFamily = WS_AF_IRDA;
-        memcpy( win->irdaDeviceID, &uin->sir_addr, sizeof(win->irdaDeviceID) );
-        if (uin->sir_lsap_sel != LSAP_ANY)
-            sprintf( win->irdaServiceName, "LSAP-SEL%u", uin->sir_lsap_sel );
-        else
-            memcpy( win->irdaServiceName, uin->sir_name,
-                    sizeof(win->irdaServiceName) );
-        return 0;
-    }
-#endif
-    case AF_INET6: {
-        const struct sockaddr_in6* uin6 = (const struct sockaddr_in6*)uaddr;
-        struct WS_sockaddr_in6 *win6 = (struct WS_sockaddr_in6 *)wsaddr;
-
-        if (*wsaddrlen < sizeof(struct WS_sockaddr_in6))
-            return -1;
-        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 */
-#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
-        win6->sin6_scope_id = uin6->sin6_scope_id;
-#else
-        win6->sin6_scope_id = 0;
-#endif
-        *wsaddrlen = sizeof(struct WS_sockaddr_in6);
-        return 0;
-    }
-    case AF_INET: {
-        const struct sockaddr_in* uin = (const 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 */
-        memset(win->sin_zero, 0, 8); /* Make sure the null padding is null */
-        *wsaddrlen = sizeof(struct WS_sockaddr_in);
-        return 0;
-    }
-    case AF_UNSPEC: {
-        memset(wsaddr,0,*wsaddrlen);
-        return 0;
-    }
-    default:
-        FIXME("Unknown address family %d\n", uaddr->sa_family);
-        return -1;
-    }
-    return res;
-}
-
 static INT WS_DuplicateSocket(BOOL unicode, SOCKET s, DWORD dwProcessId, LPWSAPROTOCOL_INFOW lpProtocolInfo)
 {
     HANDLE hProcess;
diff --git a/dlls/ws2_32/tests/protocol.c b/dlls/ws2_32/tests/protocol.c
index 99c78873d9a..1f039e509da 100644
--- a/dlls/ws2_32/tests/protocol.c
+++ b/dlls/ws2_32/tests/protocol.c
@@ -1740,7 +1740,7 @@ static void test_GetAddrInfoW(void)
         result = NULL;
         SetLastError(0xdeadbeef);
         ret = GetAddrInfoW(localhost, NULL, &hint, &result);
-        todo_wine_if (hinttests[i].error) ok(ret == hinttests[i].error, "test %d: wrong ret %d\n", i, ret);
+        ok(ret == hinttests[i].error, "test %d: wrong ret %d\n", i, ret);
         if (!ret)
         {
             for (p = result; p; p = p->ai_next)
@@ -2293,7 +2293,7 @@ static void test_getaddrinfo(void)
         result = NULL;
         SetLastError(0xdeadbeef);
         ret = getaddrinfo("localhost", NULL, &hint, &result);
-        todo_wine_if (hinttests[i].error) ok(ret == hinttests[i].error, "test %d: wrong ret %d\n", i, ret);
+        ok(ret == hinttests[i].error, "test %d: wrong ret %d\n", i, ret);
         if (!ret)
         {
             for (p = result; p; p = p->ai_next)
diff --git a/dlls/ws2_32/unixlib.c b/dlls/ws2_32/unixlib.c
new file mode 100644
index 00000000000..4b63e8e6415
--- /dev/null
+++ b/dlls/ws2_32/unixlib.c
@@ -0,0 +1,618 @@
+/*
+ * Unix library functions
+ *
+ * Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
+ * Copyright (C) 2001 Stefan Leichter
+ * Copyright (C) 2004 Hans Leidekker
+ * Copyright (C) 2005 Marcus Meissner
+ * Copyright (C) 2006-2008 Kai Blin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#if 0
+#pragma makedep unix
+#endif
+
+#include "config.h"
+#include <errno.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+#ifdef HAVE_NETDB_H
+# include <netdb.h>
+#endif
+
+#ifdef HAVE_NETIPX_IPX_H
+# include <netipx/ipx.h>
+#elif defined(HAVE_LINUX_IPX_H)
+# ifdef HAVE_ASM_TYPES_H
+#  include <asm/types.h>
+# endif
+# ifdef HAVE_LINUX_TYPES_H
+#  include <linux/types.h>
+# endif
+# include <linux/ipx.h>
+#endif
+#if defined(SOL_IPX) || defined(SO_DEFAULT_HEADERS)
+# define HAS_IPX
+#endif
+
+#ifdef HAVE_LINUX_IRDA_H
+# ifdef HAVE_LINUX_TYPES_H
+#  include <linux/types.h>
+# endif
+# include <linux/irda.h>
+# define HAS_IRDA
+#endif
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winerror.h"
+#include "winternl.h"
+#include "winsock2.h"
+#include "ws2tcpip.h"
+#include "wsipx.h"
+#include "af_irda.h"
+#include "wine/debug.h"
+
+#include "ws2_32_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(winsock);
+
+#define MAP(x) {WS_ ## x, x}
+
+static const int addrinfo_flag_map[][2] =
+{
+    MAP( AI_PASSIVE ),
+    MAP( AI_CANONNAME ),
+    MAP( AI_NUMERICHOST ),
+#ifdef AI_NUMERICSERV
+    MAP( AI_NUMERICSERV ),
+#endif
+#ifdef AI_V4MAPPED
+    MAP( AI_V4MAPPED ),
+#endif
+    MAP( AI_ALL ),
+    MAP( AI_ADDRCONFIG ),
+};
+
+static const int family_map[][2] =
+{
+    MAP( AF_UNSPEC ),
+    MAP( AF_INET ),
+    MAP( AF_INET6 ),
+#ifdef AF_IPX
+    MAP( AF_IPX ),
+#endif
+#ifdef AF_IRDA
+    MAP( AF_IRDA ),
+#endif
+};
+
+static const int socktype_map[][2] =
+{
+    MAP( SOCK_STREAM ),
+    MAP( SOCK_DGRAM ),
+    MAP( SOCK_RAW ),
+};
+
+static const int ip_protocol_map[][2] =
+{
+    MAP( IPPROTO_IP ),
+    MAP( IPPROTO_TCP ),
+    MAP( IPPROTO_UDP ),
+    MAP( IPPROTO_IPV6 ),
+    MAP( IPPROTO_ICMP ),
+    MAP( IPPROTO_IGMP ),
+    MAP( IPPROTO_RAW ),
+    {WS_IPPROTO_IPV4, IPPROTO_IPIP},
+};
+
+#undef MAP
+
+static int addrinfo_flags_from_unix( int flags )
+{
+    int ws_flags = 0;
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(addrinfo_flag_map); ++i)
+    {
+        if (flags & addrinfo_flag_map[i][1])
+        {
+            ws_flags |= addrinfo_flag_map[i][0];
+            flags &= ~addrinfo_flag_map[i][1];
+        }
+    }
+
+    if (flags)
+        FIXME( "unhandled flags %#x\n", flags );
+    return ws_flags;
+}
+
+static int addrinfo_flags_to_unix( int flags )
+{
+    int unix_flags = 0;
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(addrinfo_flag_map); ++i)
+    {
+        if (flags & addrinfo_flag_map[i][0])
+        {
+            unix_flags |= addrinfo_flag_map[i][1];
+            flags &= ~addrinfo_flag_map[i][0];
+        }
+    }
+
+    if (flags)
+        FIXME( "unhandled flags %#x\n", flags );
+    return unix_flags;
+}
+
+static int family_from_unix( int family )
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(family_map); ++i)
+    {
+        if (family == family_map[i][1])
+            return family_map[i][0];
+    }
+
+    FIXME( "unhandled family %u\n", family );
+    return -1;
+}
+
+static int family_to_unix( int family )
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(family_map); ++i)
+    {
+        if (family == family_map[i][0])
+            return family_map[i][1];
+    }
+
+    FIXME( "unhandled family %u\n", family );
+    return -1;
+}
+
+static int socktype_from_unix( int type )
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(socktype_map); ++i)
+    {
+        if (type == socktype_map[i][1])
+            return socktype_map[i][0];
+    }
+
+    FIXME( "unhandled type %u\n", type );
+    return -1;
+}
+
+static int socktype_to_unix( int type )
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(socktype_map); ++i)
+    {
+        if (type == socktype_map[i][0])
+            return socktype_map[i][1];
+    }
+
+    FIXME( "unhandled type %u\n", type );
+    return -1;
+}
+
+static int protocol_from_unix( int protocol )
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(ip_protocol_map); ++i)
+    {
+        if (protocol == ip_protocol_map[i][1])
+            return ip_protocol_map[i][0];
+    }
+
+    if (protocol >= WS_NSPROTO_IPX && protocol <= WS_NSPROTO_IPX + 255)
+        return protocol;
+
+    FIXME( "unhandled protocol %u\n", protocol );
+    return -1;
+}
+
+static int protocol_to_unix( int protocol )
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(ip_protocol_map); ++i)
+    {
+        if (protocol == ip_protocol_map[i][0])
+            return ip_protocol_map[i][1];
+    }
+
+    if (protocol >= WS_NSPROTO_IPX && protocol <= WS_NSPROTO_IPX + 255)
+        return protocol;
+
+    FIXME( "unhandled protocol %u\n", protocol );
+    return -1;
+}
+
+static unsigned int errno_from_unix( int err )
+{
+    switch (err)
+    {
+        case EINTR:             return WSAEINTR;
+        case EBADF:             return WSAEBADF;
+        case EPERM:
+        case EACCES:            return WSAEACCES;
+        case EFAULT:            return WSAEFAULT;
+        case EINVAL:            return WSAEINVAL;
+        case EMFILE:            return WSAEMFILE;
+        case EINPROGRESS:
+        case EWOULDBLOCK:       return WSAEWOULDBLOCK;
+        case EALREADY:          return WSAEALREADY;
+        case ENOTSOCK:          return WSAENOTSOCK;
+        case EDESTADDRREQ:      return WSAEDESTADDRREQ;
+        case EMSGSIZE:          return WSAEMSGSIZE;
+        case EPROTOTYPE:        return WSAEPROTOTYPE;
+        case ENOPROTOOPT:       return WSAENOPROTOOPT;
+        case EPROTONOSUPPORT:   return WSAEPROTONOSUPPORT;
+        case ESOCKTNOSUPPORT:   return WSAESOCKTNOSUPPORT;
+        case EOPNOTSUPP:        return WSAEOPNOTSUPP;
+        case EPFNOSUPPORT:      return WSAEPFNOSUPPORT;
+        case EAFNOSUPPORT:      return WSAEAFNOSUPPORT;
+        case EADDRINUSE:        return WSAEADDRINUSE;
+        case EADDRNOTAVAIL:     return WSAEADDRNOTAVAIL;
+        case ENETDOWN:          return WSAENETDOWN;
+        case ENETUNREACH:       return WSAENETUNREACH;
+        case ENETRESET:         return WSAENETRESET;
+        case ECONNABORTED:      return WSAECONNABORTED;
+        case EPIPE:
+        case ECONNRESET:        return WSAECONNRESET;
+        case ENOBUFS:           return WSAENOBUFS;
+        case EISCONN:           return WSAEISCONN;
+        case ENOTCONN:          return WSAENOTCONN;
+        case ESHUTDOWN:         return WSAESHUTDOWN;
+        case ETOOMANYREFS:      return WSAETOOMANYREFS;
+        case ETIMEDOUT:         return WSAETIMEDOUT;
+        case ECONNREFUSED:      return WSAECONNREFUSED;
+        case ELOOP:             return WSAELOOP;
+        case ENAMETOOLONG:      return WSAENAMETOOLONG;
+        case EHOSTDOWN:         return WSAEHOSTDOWN;
+        case EHOSTUNREACH:      return WSAEHOSTUNREACH;
+        case ENOTEMPTY:         return WSAENOTEMPTY;
+#ifdef EPROCLIM
+        case EPROCLIM:          return WSAEPROCLIM;
+#endif
+#ifdef EUSERS
+        case EUSERS:            return WSAEUSERS;
+#endif
+#ifdef EDQUOT
+        case EDQUOT:            return WSAEDQUOT;
+#endif
+#ifdef ESTALE
+        case ESTALE:            return WSAESTALE;
+#endif
+#ifdef EREMOTE
+        case EREMOTE:           return WSAEREMOTE;
+#endif
+        default:
+            FIXME( "unknown error: %s", strerror( err ) );
+            return WSAEFAULT;
+    }
+}
+
+static int addrinfo_err_from_unix( int err )
+{
+    switch (err)
+    {
+        case EAI_AGAIN:     return WS_EAI_AGAIN;
+        case EAI_BADFLAGS:  return WS_EAI_BADFLAGS;
+        case EAI_FAIL:      return WS_EAI_FAIL;
+        case EAI_FAMILY:    return WS_EAI_FAMILY;
+        case EAI_MEMORY:    return WS_EAI_MEMORY;
+        /* EAI_NODATA is deprecated, but still used by Windows and Linux. We map
+         * the newer EAI_NONAME to EAI_NODATA for now until Windows changes too. */
+#ifdef EAI_NODATA
+        case EAI_NODATA:    return WS_EAI_NODATA;
+#endif
+#ifdef EAI_NONAME
+        case EAI_NONAME:    return WS_EAI_NODATA;
+#endif
+        case EAI_SERVICE:   return WS_EAI_SERVICE;
+        case EAI_SOCKTYPE:  return WS_EAI_SOCKTYPE;
+        case EAI_SYSTEM:
+            /* some broken versions of glibc return EAI_SYSTEM and set errno to
+             * 0 instead of returning EAI_NONAME */
+            return errno ? errno_from_unix( errno ) : WS_EAI_NONAME;
+
+        default:
+            FIXME( "unhandled error %d\n", err );
+            return err;
+    }
+}
+
+union unix_sockaddr
+{
+    struct sockaddr addr;
+    struct sockaddr_in in;
+    struct sockaddr_in6 in6;
+#ifdef HAS_IPX
+    struct sockaddr_ipx ipx;
+#endif
+#ifdef HAS_IRDA
+    struct sockaddr_irda irda;
+#endif
+};
+
+/* different from the version in ntdll and server; it does not return failure if
+ * given a short buffer */
+static int sockaddr_from_unix( const union unix_sockaddr *uaddr, struct WS_sockaddr *wsaddr, socklen_t wsaddrlen )
+{
+    memset( wsaddr, 0, wsaddrlen );
+
+    switch (uaddr->addr.sa_family)
+    {
+    case AF_INET:
+    {
+        struct WS_sockaddr_in win = {0};
+
+        if (wsaddrlen >= sizeof(win))
+        {
+            win.sin_family = WS_AF_INET;
+            win.sin_port = uaddr->in.sin_port;
+            memcpy( &win.sin_addr, &uaddr->in.sin_addr, sizeof(win.sin_addr) );
+            memcpy( wsaddr, &win, sizeof(win) );
+        }
+        return sizeof(win);
+    }
+
+    case AF_INET6:
+    {
+        struct WS_sockaddr_in6 win = {0};
+
+        if (wsaddrlen >= sizeof(win))
+        {
+            win.sin6_family = WS_AF_INET6;
+            win.sin6_port = uaddr->in6.sin6_port;
+            win.sin6_flowinfo = uaddr->in6.sin6_flowinfo;
+            memcpy( &win.sin6_addr, &uaddr->in6.sin6_addr, sizeof(win.sin6_addr) );
+#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
+            win.sin6_scope_id = uaddr->in6.sin6_scope_id;
+#endif
+            memcpy( wsaddr, &win, sizeof(win) );
+        }
+        return sizeof(win);
+    }
+
+#ifdef HAS_IPX
+    case AF_IPX:
+    {
+        struct WS_sockaddr_ipx win = {0};
+
+        if (wsaddrlen >= sizeof(win))
+        {
+            win.sa_family = WS_AF_IPX;
+            memcpy( win.sa_netnum, &uaddr->ipx.sipx_network, sizeof(win.sa_netnum) );
+            memcpy( win.sa_nodenum, &uaddr->ipx.sipx_node, sizeof(win.sa_nodenum) );
+            win.sa_socket = uaddr->ipx.sipx_port;
+            memcpy( wsaddr, &win, sizeof(win) );
+        }
+        return sizeof(win);
+    }
+#endif
+
+#ifdef HAS_IRDA
+    case AF_IRDA:
+    {
+        SOCKADDR_IRDA win;
+
+        if (wsaddrlen >= sizeof(win))
+        {
+            win.irdaAddressFamily = WS_AF_IRDA;
+            memcpy( win.irdaDeviceID, &uaddr->irda.sir_addr, sizeof(win.irdaDeviceID) );
+            if (uaddr->irda.sir_lsap_sel != LSAP_ANY)
+                snprintf( win.irdaServiceName, sizeof(win.irdaServiceName), "LSAP-SEL%u", uaddr->irda.sir_lsap_sel );
+            else
+                memcpy( win.irdaServiceName, uaddr->irda.sir_name, sizeof(win.irdaServiceName) );
+            memcpy( wsaddr, &win, sizeof(win) );
+        }
+        return sizeof(win);
+    }
+#endif
+
+    case AF_UNSPEC:
+        return 0;
+
+    default:
+        FIXME( "unknown address family %d\n", uaddr->addr.sa_family );
+        return 0;
+    }
+}
+
+static BOOL addrinfo_in_list( const struct WS_addrinfo *list, const struct WS_addrinfo *ai )
+{
+    const struct WS_addrinfo *cursor = list;
+    while (cursor)
+    {
+        if (ai->ai_flags == cursor->ai_flags &&
+            ai->ai_family == cursor->ai_family &&
+            ai->ai_socktype == cursor->ai_socktype &&
+            ai->ai_protocol == cursor->ai_protocol &&
+            ai->ai_addrlen == cursor->ai_addrlen &&
+            !memcmp( ai->ai_addr, cursor->ai_addr, ai->ai_addrlen ) &&
+            ((ai->ai_canonname && cursor->ai_canonname && !strcmp( ai->ai_canonname, cursor->ai_canonname ))
+            || (!ai->ai_canonname && !cursor->ai_canonname)))
+        {
+            return TRUE;
+        }
+        cursor = cursor->ai_next;
+    }
+    return FALSE;
+}
+
+static int CDECL unix_getaddrinfo( const char *node, const char *service,
+                                   const struct WS_addrinfo *hints, struct WS_addrinfo **info )
+{
+#ifdef HAVE_GETADDRINFO
+    struct addrinfo unix_hints = {0};
+    struct addrinfo *unix_info, *src;
+    struct WS_addrinfo *dst, *prev = NULL;
+    int ret;
+
+    *info = NULL;
+
+    /* servname tweak required by OSX and BSD kernels */
+    if (service && !service[0]) service = "0";
+
+    if (hints)
+    {
+        unix_hints.ai_flags = addrinfo_flags_to_unix( hints->ai_flags );
+
+        if (hints->ai_family)
+            unix_hints.ai_family = family_to_unix( hints->ai_family );
+
+        if (hints->ai_socktype)
+        {
+            if ((unix_hints.ai_socktype = socktype_to_unix( hints->ai_socktype )) < 0)
+                return WSAESOCKTNOSUPPORT;
+        }
+
+        if (hints->ai_protocol)
+            unix_hints.ai_protocol = max( protocol_to_unix( hints->ai_protocol ), 0 );
+
+        /* Windows allows some invalid combinations */
+        if (unix_hints.ai_protocol == IPPROTO_TCP
+                && unix_hints.ai_socktype != SOCK_STREAM
+                && unix_hints.ai_socktype != SOCK_SEQPACKET)
+        {
+            WARN( "ignoring invalid type %u for TCP\n", unix_hints.ai_socktype );
+            unix_hints.ai_socktype = 0;
+        }
+        else if (unix_hints.ai_protocol == IPPROTO_UDP && unix_hints.ai_socktype != SOCK_DGRAM)
+        {
+            WARN( "ignoring invalid type %u for UDP\n", unix_hints.ai_socktype );
+            unix_hints.ai_socktype = 0;
+        }
+        else if (unix_hints.ai_protocol >= WS_NSPROTO_IPX && unix_hints.ai_protocol <= WS_NSPROTO_IPX + 255
+                && unix_hints.ai_socktype != SOCK_DGRAM)
+        {
+            WARN( "ignoring invalid type %u for IPX\n", unix_hints.ai_socktype );
+            unix_hints.ai_socktype = 0;
+        }
+        else if (unix_hints.ai_protocol == IPPROTO_IPV6)
+        {
+            WARN( "ignoring protocol IPv6\n" );
+            unix_hints.ai_protocol = 0;
+        }
+    }
+
+    ret = getaddrinfo( node, service, hints ? &unix_hints : NULL, &unix_info );
+    if (ret)
+        return addrinfo_err_from_unix( ret );
+
+    *info = NULL;
+
+    for (src = unix_info; src != NULL; src = src->ai_next)
+    {
+        if (!(dst = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dst) )))
+            goto fail;
+
+        dst->ai_flags = addrinfo_flags_from_unix( src->ai_flags );
+        dst->ai_family = family_from_unix( src->ai_family );
+        if (hints)
+        {
+            dst->ai_socktype = hints->ai_socktype;
+            dst->ai_protocol = hints->ai_protocol;
+        }
+        else
+        {
+            dst->ai_socktype = socktype_from_unix( src->ai_socktype );
+            dst->ai_protocol = protocol_from_unix( src->ai_protocol );
+        }
+        if (src->ai_canonname)
+        {
+            if (!(dst->ai_canonname = RtlAllocateHeap( GetProcessHeap(), 0, strlen( src->ai_canonname ) + 1 )))
+            {
+                RtlFreeHeap( GetProcessHeap(), 0, dst );
+                goto fail;
+            }
+            strcpy( dst->ai_canonname, src->ai_canonname );
+        }
+
+        dst->ai_addrlen = sockaddr_from_unix( (const union unix_sockaddr *)src->ai_addr, NULL, 0 );
+        if (!(dst->ai_addr = RtlAllocateHeap( GetProcessHeap(), 0, dst->ai_addrlen )))
+        {
+            RtlFreeHeap( GetProcessHeap(), 0, dst->ai_canonname );
+            RtlFreeHeap( GetProcessHeap(), 0, dst );
+            goto fail;
+        }
+        sockaddr_from_unix( (const union unix_sockaddr *)src->ai_addr, dst->ai_addr, dst->ai_addrlen );
+
+        if (addrinfo_in_list( *info, dst ))
+        {
+            RtlFreeHeap( GetProcessHeap(), 0, dst->ai_canonname );
+            RtlFreeHeap( GetProcessHeap(), 0, dst->ai_addr );
+            RtlFreeHeap( GetProcessHeap(), 0, dst );
+        }
+        else
+        {
+            if (prev)
+                prev->ai_next = dst;
+            else
+                *info = dst;
+            prev = dst;
+        }
+    }
+
+    freeaddrinfo( unix_info );
+    return 0;
+
+fail:
+    dst = *info;
+    while (dst)
+    {
+        struct WS_addrinfo *next;
+
+        RtlFreeHeap( GetProcessHeap(), 0, dst->ai_canonname );
+        RtlFreeHeap( GetProcessHeap(), 0, dst->ai_addr );
+        next = dst->ai_next;
+        RtlFreeHeap( GetProcessHeap(), 0, dst );
+        dst = next;
+    }
+    return WS_EAI_MEMORY;
+#else
+    FIXME( "getaddrinfo() not found during build time\n" );
+    return WS_EAI_FAIL;
+#endif
+}
+
+static const struct unix_funcs funcs =
+{
+    unix_getaddrinfo,
+};
+
+NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
+{
+    if (reason != DLL_PROCESS_ATTACH) return STATUS_SUCCESS;
+
+    *(const struct unix_funcs **)ptr_out = &funcs;
+    return STATUS_SUCCESS;
+}
diff --git a/dlls/ws2_32/ws2_32_private.h b/dlls/ws2_32/ws2_32_private.h
index b70f4a1595d..5fd083eac31 100644
--- a/dlls/ws2_32/ws2_32_private.h
+++ b/dlls/ws2_32/ws2_32_private.h
@@ -172,10 +172,6 @@ union generic_unix_sockaddr
 };
 
 int convert_eai_u2w( int ret ) DECLSPEC_HIDDEN;
-int convert_socktype_u2w( int type ) DECLSPEC_HIDDEN;
-int convert_socktype_w2u( int type ) DECLSPEC_HIDDEN;
-int ws_sockaddr_u2ws( const struct sockaddr *unix_addr, struct WS_sockaddr *win_addr,
-                      int *win_addr_len ) DECLSPEC_HIDDEN;
 unsigned int ws_sockaddr_ws2u( const struct WS_sockaddr *win_addr, int win_addr_len,
                                union generic_unix_sockaddr *unix_addr ) DECLSPEC_HIDDEN;
 
@@ -200,4 +196,12 @@ extern int num_startup;
 
 struct per_thread_data *get_per_thread_data(void) DECLSPEC_HIDDEN;
 
+struct unix_funcs
+{
+    int (CDECL *getaddrinfo)( const char *node, const char *service,
+                              const struct WS(addrinfo) *hints, struct WS(addrinfo) **info );
+};
+
+extern const struct unix_funcs *unix_funcs;
+
 #endif
-- 
2.32.0




More information about the wine-devel mailing list