ws2_32: Fix WSADuplicateSocket implementation.
This commit is contained in:
parent
31f8893678
commit
d71bf64e87
|
@ -395,6 +395,7 @@ static struct WS_hostent *WS_create_he(char *name, int aliases, int aliases_size
|
||||||
static struct WS_hostent *WS_dup_he(const struct hostent* p_he);
|
static struct WS_hostent *WS_dup_he(const struct hostent* p_he);
|
||||||
static struct WS_protoent *WS_dup_pe(const struct protoent* p_pe);
|
static struct WS_protoent *WS_dup_pe(const struct protoent* p_pe);
|
||||||
static struct WS_servent *WS_dup_se(const struct servent* p_se);
|
static struct WS_servent *WS_dup_se(const struct servent* p_se);
|
||||||
|
static int ws_protocol_info(SOCKET s, int unicode, WSAPROTOCOL_INFOW *buffer, int *size);
|
||||||
|
|
||||||
int WSAIOCTL_GetInterfaceCount(void);
|
int WSAIOCTL_GetInterfaceCount(void);
|
||||||
int WSAIOCTL_GetInterfaceName(int intNumber, char *intName);
|
int WSAIOCTL_GetInterfaceName(int intNumber, char *intName);
|
||||||
|
@ -1549,18 +1550,35 @@ static int ws_sockaddr_u2ws(const struct sockaddr* uaddr, struct WS_sockaddr* ws
|
||||||
static INT WS_DuplicateSocket(BOOL unicode, SOCKET s, DWORD dwProcessId, LPWSAPROTOCOL_INFOW lpProtocolInfo)
|
static INT WS_DuplicateSocket(BOOL unicode, SOCKET s, DWORD dwProcessId, LPWSAPROTOCOL_INFOW lpProtocolInfo)
|
||||||
{
|
{
|
||||||
HANDLE hProcess;
|
HANDLE hProcess;
|
||||||
|
int size;
|
||||||
|
WSAPROTOCOL_INFOW infow;
|
||||||
|
|
||||||
TRACE("(unicode %d, socket %04lx, processid %x, buffer %p)\n",
|
TRACE("(unicode %d, socket %04lx, processid %x, buffer %p)\n",
|
||||||
unicode, s, dwProcessId, lpProtocolInfo);
|
unicode, s, dwProcessId, lpProtocolInfo);
|
||||||
memset(lpProtocolInfo, 0, unicode ? sizeof(WSAPROTOCOL_INFOW) : sizeof(WSAPROTOCOL_INFOA));
|
|
||||||
/* FIXME: WS_getsockopt(s, WS_SOL_SOCKET, SO_PROTOCOL_INFO, lpProtocolInfo, sizeof(*lpProtocolInfo)); */
|
if (!ws_protocol_info(s, unicode, &infow, &size))
|
||||||
|
return SOCKET_ERROR;
|
||||||
|
|
||||||
|
if (!(hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, dwProcessId)))
|
||||||
|
{
|
||||||
|
SetLastError(WSAEINVAL);
|
||||||
|
return SOCKET_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lpProtocolInfo)
|
||||||
|
{
|
||||||
|
CloseHandle(hProcess);
|
||||||
|
SetLastError(WSAEFAULT);
|
||||||
|
return SOCKET_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
/* I don't know what the real Windoze does next, this is a hack */
|
/* I don't know what the real Windoze does next, this is a hack */
|
||||||
/* ...we could duplicate and then use ConvertToGlobalHandle on the duplicate, then let
|
/* ...we could duplicate and then use ConvertToGlobalHandle on the duplicate, then let
|
||||||
* the target use the global duplicate, or we could copy a reference to us to the structure
|
* the target use the global duplicate, or we could copy a reference to us to the structure
|
||||||
* and let the target duplicate it from us, but let's do it as simple as possible */
|
* and let the target duplicate it from us, but let's do it as simple as possible */
|
||||||
hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, dwProcessId);
|
memcpy(lpProtocolInfo, &infow, size);
|
||||||
DuplicateHandle(GetCurrentProcess(), SOCKET2HANDLE(s),
|
DuplicateHandle(GetCurrentProcess(), SOCKET2HANDLE(s),
|
||||||
hProcess, (LPHANDLE)&lpProtocolInfo->dwCatalogEntryId,
|
hProcess, (LPHANDLE)&lpProtocolInfo->dwServiceFlags3,
|
||||||
0, FALSE, DUPLICATE_SAME_ACCESS);
|
0, FALSE, DUPLICATE_SAME_ACCESS);
|
||||||
CloseHandle(hProcess);
|
CloseHandle(hProcess);
|
||||||
lpProtocolInfo->dwServiceFlags4 = 0xff00ff00; /* magic */
|
lpProtocolInfo->dwServiceFlags4 = 0xff00ff00; /* magic */
|
||||||
|
@ -1769,7 +1787,8 @@ static BOOL ws_protocol_info(SOCKET s, int unicode, WSAPROTOCOL_INFOW *buffer, i
|
||||||
|
|
||||||
if (status)
|
if (status)
|
||||||
{
|
{
|
||||||
set_error(status);
|
unsigned int err = NtStatusToWSAError( status );
|
||||||
|
SetLastError( err == WSAEBADF ? WSAENOTSOCK : err );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5855,7 +5874,7 @@ SOCKET WINAPI WSASocketW(int af, int type, int protocol,
|
||||||
|
|
||||||
/* hack for WSADuplicateSocket */
|
/* hack for WSADuplicateSocket */
|
||||||
if (lpProtocolInfo && lpProtocolInfo->dwServiceFlags4 == 0xff00ff00) {
|
if (lpProtocolInfo && lpProtocolInfo->dwServiceFlags4 == 0xff00ff00) {
|
||||||
ret = lpProtocolInfo->dwCatalogEntryId;
|
ret = lpProtocolInfo->dwServiceFlags3;
|
||||||
TRACE("\tgot duplicate %04lx\n", ret);
|
TRACE("\tgot duplicate %04lx\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1968,6 +1968,167 @@ todo_wine
|
||||||
HeapFree(GetProcessHeap(), 0, pi);
|
HeapFree(GetProcessHeap(), 0, pi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_WSADuplicateSocket(void)
|
||||||
|
{
|
||||||
|
SOCKET source, dupsock;
|
||||||
|
WSAPROTOCOL_INFOA info;
|
||||||
|
DWORD err;
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
int socktype, size, addrsize;
|
||||||
|
char teststr[] = "TEST", buffer[16];
|
||||||
|
|
||||||
|
source = WSASocketA(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
|
||||||
|
ok(source != INVALID_SOCKET, "WSASocketA should have succeeded\n");
|
||||||
|
|
||||||
|
/* test invalid parameters */
|
||||||
|
SetLastError(0xdeadbeef);
|
||||||
|
ok(WSADuplicateSocketA(0, 0, NULL), "WSADuplicateSocketA should have failed\n");
|
||||||
|
err = WSAGetLastError();
|
||||||
|
ok(err == WSAENOTSOCK, "expected 10038, received %d\n", err);
|
||||||
|
|
||||||
|
SetLastError(0xdeadbeef);
|
||||||
|
ok(WSADuplicateSocketA(source, 0, NULL),
|
||||||
|
"WSADuplicateSocketA should have failed\n");
|
||||||
|
err = WSAGetLastError();
|
||||||
|
ok(err == WSAEINVAL, "expected 10022, received %d\n", err);
|
||||||
|
|
||||||
|
SetLastError(0xdeadbeef);
|
||||||
|
ok(WSADuplicateSocketA(source, ~0, &info),
|
||||||
|
"WSADuplicateSocketA should have failed\n");
|
||||||
|
err = WSAGetLastError();
|
||||||
|
ok(err == WSAEINVAL, "expected 10022, received %d\n", err);
|
||||||
|
|
||||||
|
SetLastError(0xdeadbeef);
|
||||||
|
ok(WSADuplicateSocketA(0, GetCurrentProcessId(), &info),
|
||||||
|
"WSADuplicateSocketA should have failed\n");
|
||||||
|
err = WSAGetLastError();
|
||||||
|
ok(err == WSAENOTSOCK, "expected 10038, received %d\n", err);
|
||||||
|
|
||||||
|
SetLastError(0xdeadbeef);
|
||||||
|
ok(WSADuplicateSocketA(source, GetCurrentProcessId(), NULL),
|
||||||
|
"WSADuplicateSocketA should have failed\n");
|
||||||
|
err = WSAGetLastError();
|
||||||
|
ok(err == WSAEFAULT, "expected 10014, received %d\n", err);
|
||||||
|
|
||||||
|
/* test returned structure */
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
ok(!WSADuplicateSocketA(source, GetCurrentProcessId(), &info),
|
||||||
|
"WSADuplicateSocketA should have worked\n");
|
||||||
|
|
||||||
|
ok(info.iProtocol == IPPROTO_TCP, "expected protocol %d, received %d\n",
|
||||||
|
IPPROTO_TCP, info.iProtocol);
|
||||||
|
ok(info.iAddressFamily == AF_INET, "expected family %d, received %d\n",
|
||||||
|
AF_INET, info.iProtocol);
|
||||||
|
ok(info.iSocketType == SOCK_STREAM, "expected protocol %d, received %d\n",
|
||||||
|
SOCK_STREAM, info.iSocketType);
|
||||||
|
|
||||||
|
dupsock = WSASocketA(0, 0, 0, &info, 0, 0);
|
||||||
|
ok(dupsock != INVALID_SOCKET, "WSASocketA should have succeeded\n");
|
||||||
|
|
||||||
|
closesocket(dupsock);
|
||||||
|
closesocket(source);
|
||||||
|
|
||||||
|
/* create a socket, bind it, duplicate it then send data on source and
|
||||||
|
* receve in the duplicated socket */
|
||||||
|
source = WSASocketA(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, 0);
|
||||||
|
ok(source != INVALID_SOCKET, "WSASocketA should have succeeded\n");
|
||||||
|
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
ok(!WSADuplicateSocketA(source, GetCurrentProcessId(), &info),
|
||||||
|
"WSADuplicateSocketA should have worked\n");
|
||||||
|
|
||||||
|
ok(info.iProtocol == IPPROTO_UDP, "expected protocol %d, received %d\n",
|
||||||
|
IPPROTO_UDP, info.iProtocol);
|
||||||
|
ok(info.iAddressFamily == AF_INET, "expected family %d, received %d\n",
|
||||||
|
AF_INET, info.iProtocol);
|
||||||
|
ok(info.iSocketType == SOCK_DGRAM, "expected protocol %d, received %d\n",
|
||||||
|
SOCK_DGRAM, info.iSocketType);
|
||||||
|
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||||
|
ok(!bind(source, (struct sockaddr*)&addr, sizeof(addr)),
|
||||||
|
"bind should have worked\n");
|
||||||
|
|
||||||
|
/* read address to find out the port number to be used in sendto */
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addrsize = sizeof(addr);
|
||||||
|
ok(!getsockname(source, (struct sockaddr *) &addr, &addrsize),
|
||||||
|
"getsockname should have worked\n");
|
||||||
|
ok(addr.sin_port, "socket port should be != 0\n");
|
||||||
|
|
||||||
|
dupsock = WSASocketA(0, 0, 0, &info, 0, 0);
|
||||||
|
ok(dupsock != INVALID_SOCKET, "WSASocketA should have succeeded\n");
|
||||||
|
|
||||||
|
size = sizeof(int);
|
||||||
|
ok(!getsockopt(dupsock, SOL_SOCKET, SO_TYPE, (char *) &socktype, &size),
|
||||||
|
"getsockopt failed with %d\n", WSAGetLastError());
|
||||||
|
ok(socktype == SOCK_DGRAM, "Wrong socket type, expected %d received %d\n",
|
||||||
|
SOCK_DGRAM, socktype);
|
||||||
|
|
||||||
|
set_blocking(source, TRUE);
|
||||||
|
|
||||||
|
/* send data on source socket */
|
||||||
|
addrsize = sizeof(addr);
|
||||||
|
size = sendto(source, teststr, sizeof(teststr), 0, (struct sockaddr *) &addr, addrsize);
|
||||||
|
ok(size == sizeof(teststr), "got %d (err %d)\n", size, WSAGetLastError());
|
||||||
|
|
||||||
|
/* receive on duplicated socket */
|
||||||
|
addrsize = sizeof(addr);
|
||||||
|
memset(buffer, 0, sizeof(buffer));
|
||||||
|
size = recvfrom(dupsock, buffer, sizeof(teststr), 0, (struct sockaddr *) &addr, &addrsize);
|
||||||
|
ok(size == sizeof(teststr), "got %d (err %d)\n", size, WSAGetLastError());
|
||||||
|
buffer[sizeof(teststr) - 1] = 0;
|
||||||
|
ok(!strcmp(buffer, teststr), "expected '%s', received '%s'\n", teststr, buffer);
|
||||||
|
|
||||||
|
closesocket(dupsock);
|
||||||
|
closesocket(source);
|
||||||
|
|
||||||
|
/* show that the source socket need to be bound before the duplicated
|
||||||
|
* socket is created */
|
||||||
|
source = WSASocketA(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, 0);
|
||||||
|
ok(source != INVALID_SOCKET, "WSASocketA should have succeeded\n");
|
||||||
|
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
ok(!WSADuplicateSocketA(source, GetCurrentProcessId(), &info),
|
||||||
|
"WSADuplicateSocketA should have worked\n");
|
||||||
|
|
||||||
|
dupsock = WSASocketA(0, 0, 0, &info, 0, 0);
|
||||||
|
ok(dupsock != INVALID_SOCKET, "WSASocketA should have succeeded\n");
|
||||||
|
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||||
|
ok(!bind(source, (struct sockaddr*)&addr, sizeof(addr)),
|
||||||
|
"bind should have worked\n");
|
||||||
|
|
||||||
|
/* read address to find out the port number to be used in sendto */
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addrsize = sizeof(addr);
|
||||||
|
ok(!getsockname(source, (struct sockaddr *) &addr, &addrsize),
|
||||||
|
"getsockname should have worked\n");
|
||||||
|
ok(addr.sin_port, "socket port should be != 0\n");
|
||||||
|
|
||||||
|
set_blocking(source, TRUE);
|
||||||
|
|
||||||
|
addrsize = sizeof(addr);
|
||||||
|
size = sendto(source, teststr, sizeof(teststr), 0, (struct sockaddr *) &addr, addrsize);
|
||||||
|
ok(size == sizeof(teststr), "got %d (err %d)\n", size, WSAGetLastError());
|
||||||
|
|
||||||
|
SetLastError(0xdeadbeef);
|
||||||
|
addrsize = sizeof(addr);
|
||||||
|
memset(buffer, 0, sizeof(buffer));
|
||||||
|
todo_wine {
|
||||||
|
ok(recvfrom(dupsock, buffer, sizeof(teststr), 0, (struct sockaddr *) &addr, &addrsize) == -1,
|
||||||
|
"recvfrom should have failed\n");
|
||||||
|
err = WSAGetLastError();
|
||||||
|
ok(err == WSAEINVAL, "expected 10022, received %d\n", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
closesocket(dupsock);
|
||||||
|
closesocket(source);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_WSAAddressToStringA(void)
|
static void test_WSAAddressToStringA(void)
|
||||||
{
|
{
|
||||||
SOCKET v6 = INVALID_SOCKET;
|
SOCKET v6 = INVALID_SOCKET;
|
||||||
|
@ -6435,6 +6596,7 @@ START_TEST( sock )
|
||||||
|
|
||||||
test_getservbyname();
|
test_getservbyname();
|
||||||
test_WSASocket();
|
test_WSASocket();
|
||||||
|
test_WSADuplicateSocket();
|
||||||
|
|
||||||
test_WSAAddressToStringA();
|
test_WSAAddressToStringA();
|
||||||
test_WSAAddressToStringW();
|
test_WSAAddressToStringW();
|
||||||
|
|
Loading…
Reference in New Issue