[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