diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index d82172aa5ba..aa0a164ff93 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -6997,6 +6997,7 @@ static struct WS_addrinfo *addrinfo_WtoA(const struct WS_addrinfoW *ai) struct getaddrinfo_args { OVERLAPPED *overlapped; + LPLOOKUPSERVICE_COMPLETION_ROUTINE completion_routine; ADDRINFOEXW **result; char *nodename; char *servname; @@ -7007,6 +7008,7 @@ static void WINAPI getaddrinfo_callback(TP_CALLBACK_INSTANCE *instance, void *co struct getaddrinfo_args *args = context; OVERLAPPED *overlapped = args->overlapped; HANDLE event = overlapped->hEvent; + LPLOOKUPSERVICE_COMPLETION_ROUTINE completion_routine = args->completion_routine; struct WS_addrinfo *res; int ret; @@ -7023,10 +7025,12 @@ static void WINAPI getaddrinfo_callback(TP_CALLBACK_INSTANCE *instance, void *co HeapFree(GetProcessHeap(), 0, args); overlapped->Internal = ret; + if (completion_routine) completion_routine(ret, 0, overlapped); if (event) SetEvent(event); } -static int WS_getaddrinfoW(const WCHAR *nodename, const WCHAR *servname, const struct WS_addrinfo *hints, ADDRINFOEXW **res, OVERLAPPED *overlapped) +static int WS_getaddrinfoW(const WCHAR *nodename, const WCHAR *servname, const struct WS_addrinfo *hints, ADDRINFOEXW **res, + OVERLAPPED *overlapped, LPLOOKUPSERVICE_COMPLETION_ROUTINE completion_routine) { int ret = EAI_MEMORY, len, i; char *nodenameA = NULL, *servnameA = NULL; @@ -7082,8 +7086,15 @@ static int WS_getaddrinfoW(const WCHAR *nodename, const WCHAR *servname, const s { struct getaddrinfo_args *args; + if (overlapped->hEvent && completion_routine) + { + ret = WSAEINVAL; + goto end; + } + if (!(args = HeapAlloc(GetProcessHeap(), 0, sizeof(*args)))) goto end; args->overlapped = overlapped; + args->completion_routine = completion_routine; args->result = res; args->nodename = nodenameA; args->servname = servnameA; @@ -7096,7 +7107,6 @@ static int WS_getaddrinfoW(const WCHAR *nodename, const WCHAR *servname, const s goto end; } - if (local_nodenameW != nodename) HeapFree(GetProcessHeap(), 0, local_nodenameW); WSASetLastError(ERROR_IO_PENDING); @@ -7138,12 +7148,10 @@ int WINAPI GetAddrInfoExW(const WCHAR *name, const WCHAR *servname, DWORD namesp FIXME("Unsupported hints\n"); if (timeout) FIXME("Unsupported timeout\n"); - if (completion_routine) - FIXME("Unsupported completion_routine\n"); if (handle) FIXME("Unsupported cancel handle\n"); - ret = WS_getaddrinfoW(name, servname, NULL, result, overlapped); + ret = WS_getaddrinfoW(name, servname, NULL, result, overlapped, completion_routine); if (ret) return ret; if (handle) *handle = (HANDLE)0xdeadbeef; return 0; @@ -7181,7 +7189,7 @@ int WINAPI GetAddrInfoW(LPCWSTR nodename, LPCWSTR servname, const ADDRINFOW *hin *res = NULL; if (hints) hintsA = addrinfo_WtoA(hints); - ret = WS_getaddrinfoW(nodename, servname, hintsA, &resex, NULL); + ret = WS_getaddrinfoW(nodename, servname, hintsA, &resex, NULL, NULL); WS_freeaddrinfo(hintsA); if (ret) return ret; diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index e97cd381d0e..e4b57cfddae 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -7617,11 +7617,36 @@ static void test_GetAddrInfoW(void) ok(result2 == NULL, "got %p\n", result2); } +static struct completion_routine_test +{ + WSAOVERLAPPED *overlapped; + DWORD error; + ADDRINFOEXW **result; + HANDLE event; + DWORD called; +} completion_routine_test; + +static void CALLBACK completion_routine(DWORD error, DWORD byte_count, WSAOVERLAPPED *overlapped) +{ + struct completion_routine_test *test = &completion_routine_test; + + ok(error == test->error, "got %u\n", error); + ok(!byte_count, "got %u\n", byte_count); + ok(overlapped == test->overlapped, "got %p\n", overlapped); + ok(overlapped->Internal == test->error, "got %lu\n", overlapped->Internal); + ok(overlapped->Pointer == test->result, "got %p\n", overlapped->Pointer); + ok(overlapped->hEvent == NULL, "got %p\n", overlapped->hEvent); + + test->called++; + SetEvent(test->event); +} + static void test_GetAddrInfoExW(void) { static const WCHAR empty[] = {0}; static const WCHAR localhost[] = {'l','o','c','a','l','h','o','s','t',0}; static const WCHAR winehq[] = {'t','e','s','t','.','w','i','n','e','h','q','.','o','r','g',0}; + static const WCHAR nxdomain[] = {'n','x','d','o','m','a','i','n','.','w','i','n','e','h','q','.','o','r','g',0}; ADDRINFOEXW *result; OVERLAPPED overlapped; HANDLE event; @@ -7706,6 +7731,53 @@ static void test_GetAddrInfoExW(void) todo_wine_if(ret != WAIT_TIMEOUT) /* Remove when abowe todo_wines are fixed */ ok(ret == WAIT_TIMEOUT, "wait failed\n"); + /* event + completion routine */ + result = (void*)0xdeadbeef; + memset(&overlapped, 0xcc, sizeof(overlapped)); + overlapped.hEvent = event; + ResetEvent(event); + ret = pGetAddrInfoExW(localhost, NULL, NS_DNS, NULL, NULL, &result, NULL, &overlapped, completion_routine, NULL); + ok(ret == WSAEINVAL, "GetAddrInfoExW failed with %d\n", WSAGetLastError()); + + /* completion routine, existing domain */ + result = (void *)0xdeadbeef; + overlapped.hEvent = NULL; + completion_routine_test.overlapped = &overlapped; + completion_routine_test.error = ERROR_SUCCESS; + completion_routine_test.result = &result; + completion_routine_test.event = event; + completion_routine_test.called = 0; + ResetEvent(event); + ret = pGetAddrInfoExW(winehq, NULL, NS_DNS, NULL, NULL, &result, NULL, &overlapped, completion_routine, NULL); + ok(ret == ERROR_IO_PENDING, "GetAddrInfoExW failed with %d\n", WSAGetLastError()); + ok(!result, "result != NULL\n"); + ok(WaitForSingleObject(event, 1000) == WAIT_OBJECT_0, "wait failed\n"); + ret = pGetAddrInfoExOverlappedResult(&overlapped); + ok(!ret, "overlapped result is %d\n", ret); + ok(overlapped.hEvent == NULL, "hEvent changed %p\n", overlapped.hEvent); + ok(overlapped.Internal == ERROR_SUCCESS, "overlapped.Internal = %lx\n", overlapped.Internal); + ok(overlapped.Pointer == &result, "overlapped.Pointer != &result\n"); + ok(completion_routine_test.called == 1, "got %u\n", completion_routine_test.called); + pFreeAddrInfoExW(result); + + /* completion routine, non-existing domain */ + result = (void *)0xdeadbeef; + completion_routine_test.overlapped = &overlapped; + completion_routine_test.error = WSAHOST_NOT_FOUND; + completion_routine_test.called = 0; + ResetEvent(event); + ret = pGetAddrInfoExW(nxdomain, NULL, NS_DNS, NULL, NULL, &result, NULL, &overlapped, completion_routine, NULL); + ok(ret == ERROR_IO_PENDING, "GetAddrInfoExW failed with %d\n", WSAGetLastError()); + ok(!result, "result != NULL\n"); + ok(WaitForSingleObject(event, 1000) == WAIT_OBJECT_0, "wait failed\n"); + ret = pGetAddrInfoExOverlappedResult(&overlapped); + ok(ret == WSAHOST_NOT_FOUND, "overlapped result is %d\n", ret); + ok(overlapped.hEvent == NULL, "hEvent changed %p\n", overlapped.hEvent); + ok(overlapped.Internal == WSAHOST_NOT_FOUND, "overlapped.Internal = %lx\n", overlapped.Internal); + ok(overlapped.Pointer == &result, "overlapped.Pointer != &result\n"); + ok(completion_routine_test.called == 1, "got %u\n", completion_routine_test.called); + ok(result == NULL, "got %p\n", result); + WSACloseEvent(event); }