ws2_32: Cope with invalid hints in getaddrinfo/GetAddrInfoW.

This commit is contained in:
Bruno Jesus 2013-12-30 23:45:07 -02:00 committed by Alexandre Julliard
parent 3eb39dc08e
commit 719715c774
2 changed files with 171 additions and 17 deletions

View file

@ -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);

View file

@ -149,6 +149,38 @@ typedef struct select_thread_params
BOOL ReadKilled;
} select_thread_params;
/* Tests used in both getaddrinfo and GetAddrInfoW */
static const 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)