[4/4] ws2_32: Cope with invalid hints in getaddrinfo/GetAddrInfoW (try 2)

Bruno Jesus 00cpxxx at gmail.com
Mon Dec 30 19:45:07 CST 2013


try2:
Sorry for the test failures.
Superseeds 101272


original:

The Windows version of getaddrinfo allows some exotic combinations of
protocol and socket type while the unix version instantly fails. So,
ensure stuff like SOCK_DGRAM + IPPROTO_TCP and other things like
non-existent protocols work.

Fixes http://bugs.winehq.org/show_bug.cgi?id=34971
-------------- next part --------------
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 462ff86..0391554 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -5464,19 +5464,33 @@ int WINAPI WS_getaddrinfo(LPCSTR nodename, LPCSTR servname, const struct WS_addr
         punixhints = &unixhints;
 
         memset(&unixhints, 0, sizeof(unixhints));
-        punixhints->ai_flags    = convert_aiflag_w2u(hints->ai_flags);
-        if (hints->ai_family == 0) /* wildcard, specific to getaddrinfo() */
-            punixhints->ai_family = 0;
-        else
+        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 == 0) /* wildcard, specific to getaddrinfo() */
-            punixhints->ai_socktype = 0;
-        else
+        if (hints->ai_socktype)
             punixhints->ai_socktype = convert_socktype_w2u(hints->ai_socktype);
-        if (hints->ai_protocol == 0) /* wildcard, specific to getaddrinfo() */
-            punixhints->ai_protocol = 0;
-        else
-            punixhints->ai_protocol = convert_proto_w2u(hints->ai_protocol);
+        if (hints->ai_protocol)
+            punixhints->ai_protocol = max(convert_proto_w2u(hints->ai_protocol), 0);
+
+        if (punixhints->ai_socktype < 0)
+        {
+            WSASetLastError(WSAESOCKTNOSUPPORT);
+            return SOCKET_ERROR;
+        }
+
+        /* 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;
     }
 
     /* getaddrinfo(3) is thread safe, no need to wrap in CS */
@@ -5500,8 +5514,14 @@ int WINAPI WS_getaddrinfo(LPCSTR nodename, LPCSTR servname, const struct WS_addr
             *xai = ai;xai = &ai->ai_next;
             ai->ai_flags    = convert_aiflag_u2w(xuai->ai_flags);
             ai->ai_family   = convert_af_u2w(xuai->ai_family);
-            ai->ai_socktype = convert_socktype_u2w(xuai->ai_socktype);
-            ai->ai_protocol = convert_proto_u2w(xuai->ai_protocol);
+            /* 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);
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index 59c356c..7078e66 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -149,6 +149,38 @@ typedef struct select_thread_params
     BOOL ReadKilled;
 } select_thread_params;
 
+/* Tests used in both getaddrinfo and GetAddrInfoW */
+static struct addr_hint_tests
+{
+    int family, socktype, protocol;
+    DWORD error;
+} hinttests[] = {
+    {AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, 0 },
+    {AF_UNSPEC, SOCK_STREAM, IPPROTO_UDP, 0 },
+    {AF_UNSPEC, SOCK_DGRAM,  IPPROTO_TCP, 0 },
+    {AF_UNSPEC, SOCK_DGRAM,  IPPROTO_UDP, 0 },
+    {AF_INET,   SOCK_STREAM, IPPROTO_TCP, 0 },
+    {AF_INET,   SOCK_STREAM, IPPROTO_UDP, 0 },
+    {AF_INET,   SOCK_DGRAM,  IPPROTO_TCP, 0 },
+    {AF_INET,   SOCK_DGRAM,  IPPROTO_UDP, 0 },
+    {AF_UNSPEC, 0,           IPPROTO_TCP, 0 },
+    {AF_UNSPEC, 0,           IPPROTO_UDP, 0 },
+    {AF_UNSPEC, SOCK_STREAM, 0,           0 },
+    {AF_UNSPEC, SOCK_DGRAM,  0,           0 },
+    {AF_INET,   0,           IPPROTO_TCP, 0 },
+    {AF_INET,   0,           IPPROTO_UDP, 0 },
+    {AF_INET,   SOCK_STREAM, 0,           0 },
+    {AF_INET,   SOCK_DGRAM,  0,           0 },
+    {AF_UNSPEC, 999,         IPPROTO_TCP, WSAESOCKTNOSUPPORT },
+    {AF_UNSPEC, 999,         IPPROTO_UDP, WSAESOCKTNOSUPPORT },
+    {AF_INET,   999,         IPPROTO_TCP, WSAESOCKTNOSUPPORT },
+    {AF_INET,   999,         IPPROTO_UDP, WSAESOCKTNOSUPPORT },
+    {AF_UNSPEC, SOCK_STREAM, 999,         0 },
+    {AF_UNSPEC, SOCK_STREAM, 999,         0 },
+    {AF_INET,   SOCK_DGRAM,  999,         0 },
+    {AF_INET,   SOCK_DGRAM,  999,         0 },
+};
+
 /**************** Static variables ***************/
 
 static DWORD      tls;              /* Thread local storage index */
@@ -5280,8 +5312,8 @@ static void test_GetAddrInfoW(void)
     static const WCHAR nxdomain[] =
         {'n','x','d','o','m','a','i','n','.','c','o','d','e','w','e','a','v','e','r','s','.','c','o','m',0};
     static const WCHAR zero[] = {'0',0};
-    int ret;
-    ADDRINFOW *result, hint;
+    int i, ret;
+    ADDRINFOW *result, *p, hint;
 
     if (!pGetAddrInfoW || !pFreeAddrInfoW)
     {
@@ -5352,12 +5384,63 @@ static void test_GetAddrInfoW(void)
     ret = pGetAddrInfoW(nxdomain, NULL, NULL, &result);
     ok(ret == WSAHOST_NOT_FOUND, "got %d expected WSAHOST_NOT_FOUND\n", ret);
     ok(result == NULL, "got %p\n", result);
+
+    for (i = 0;i < (sizeof(hinttests) / sizeof(hinttests[0]));i++)
+    {
+        hint.ai_family = hinttests[i].family;
+        hint.ai_socktype = hinttests[i].socktype;
+        hint.ai_protocol = hinttests[i].protocol;
+
+        result = NULL;
+        SetLastError(0xdeadbeef);
+        ret = pGetAddrInfoW(localhost, NULL, &hint, &result);
+        if (!ret)
+        {
+            if (hinttests[i].error)
+                ok(0, "test %d: GetAddrInfoW succeeded unexpectedly\n", i);
+            else
+            {
+                p = result;
+                do
+                {
+                    /* when AF_UNSPEC is used the return will be either AF_INET or AF_INET6 */
+                    if (hinttests[i].family == AF_UNSPEC)
+                        ok(p->ai_family == AF_INET || p->ai_family == AF_INET6,
+                           "test %d: expected AF_INET or AF_INET6, got %d\n",
+                           i, p->ai_family);
+                    else
+                        ok(p->ai_family == hinttests[i].family,
+                           "test %d: expected family %d, got %d\n",
+                           i, hinttests[i].family, p->ai_family);
+
+                    ok(p->ai_socktype == hinttests[i].socktype,
+                       "test %d: expected type %d, got %d\n",
+                       i, hinttests[i].socktype, p->ai_socktype);
+                    ok(p->ai_protocol == hinttests[i].protocol,
+                       "test %d: expected protocol %d, got %d\n",
+                       i, hinttests[i].protocol, p->ai_protocol);
+                    p = p->ai_next;
+                }
+                while (p);
+            }
+            pFreeAddrInfoW(result);
+        }
+        else
+        {
+            DWORD err = WSAGetLastError();
+            if (hinttests[i].error)
+                ok(hinttests[i].error == err, "test %d: GetAddrInfoW failed with error %d, expected %d\n",
+                   i, err, hinttests[i].error);
+            else
+                ok(0, "test %d: GetAddrInfoW failed with %d (err %d)\n", i, ret, err);
+        }
+    }
 }
 
 static void test_getaddrinfo(void)
 {
-    int ret;
-    ADDRINFOA *result, hint;
+    int i, ret;
+    ADDRINFOA *result, *p, hint;
 
     if (!pgetaddrinfo || !pfreeaddrinfo)
     {
@@ -5423,6 +5506,57 @@ static void test_getaddrinfo(void)
     ret = pgetaddrinfo("nxdomain.codeweavers.com", NULL, NULL, &result);
     ok(ret == WSAHOST_NOT_FOUND, "got %d expected WSAHOST_NOT_FOUND\n", ret);
     ok(result == NULL, "got %p\n", result);
+
+    for (i = 0;i < (sizeof(hinttests) / sizeof(hinttests[0]));i++)
+    {
+        hint.ai_family = hinttests[i].family;
+        hint.ai_socktype = hinttests[i].socktype;
+        hint.ai_protocol = hinttests[i].protocol;
+
+        result = NULL;
+        SetLastError(0xdeadbeef);
+        ret = pgetaddrinfo("localhost", NULL, &hint, &result);
+        if(!ret)
+        {
+            if (hinttests[i].error)
+                ok(0, "test %d: getaddrinfo succeeded unexpectedly\n", i);
+            else
+            {
+                p = result;
+                do
+                {
+                    /* when AF_UNSPEC is used the return will be either AF_INET or AF_INET6 */
+                    if (hinttests[i].family == AF_UNSPEC)
+                        ok(p->ai_family == AF_INET || p->ai_family == AF_INET6,
+                           "test %d: expected AF_INET or AF_INET6, got %d\n",
+                           i, p->ai_family);
+                    else
+                        ok(p->ai_family == hinttests[i].family,
+                           "test %d: expected family %d, got %d\n",
+                           i, hinttests[i].family, p->ai_family);
+
+                    ok(p->ai_socktype == hinttests[i].socktype,
+                       "test %d: expected type %d, got %d\n",
+                       i, hinttests[i].socktype, p->ai_socktype);
+                    ok(p->ai_protocol == hinttests[i].protocol,
+                       "test %d: expected protocol %d, got %d\n",
+                       i, hinttests[i].protocol, p->ai_protocol);
+                    p = p->ai_next;
+                }
+                while (p);
+            }
+            pfreeaddrinfo(result);
+        }
+        else
+        {
+            DWORD err = WSAGetLastError();
+            if (hinttests[i].error)
+                ok(hinttests[i].error == err, "test %d: getaddrinfo failed with error %d, expected %d\n",
+                   i, err, hinttests[i].error);
+            else
+                ok(0, "test %d: getaddrinfo failed with %d (err %d)\n", i, ret, err);
+        }
+    }
 }
 
 static void test_ConnectEx(void)


More information about the wine-patches mailing list