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_protoent *WS_dup_pe(const struct protoent* p_pe);
|
||||
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_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)
|
||||
{
|
||||
HANDLE hProcess;
|
||||
int size;
|
||||
WSAPROTOCOL_INFOW infow;
|
||||
|
||||
TRACE("(unicode %d, socket %04lx, processid %x, buffer %p)\n",
|
||||
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 */
|
||||
/* ...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
|
||||
* 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),
|
||||
hProcess, (LPHANDLE)&lpProtocolInfo->dwCatalogEntryId,
|
||||
hProcess, (LPHANDLE)&lpProtocolInfo->dwServiceFlags3,
|
||||
0, FALSE, DUPLICATE_SAME_ACCESS);
|
||||
CloseHandle(hProcess);
|
||||
lpProtocolInfo->dwServiceFlags4 = 0xff00ff00; /* magic */
|
||||
|
@ -1769,7 +1787,8 @@ static BOOL ws_protocol_info(SOCKET s, int unicode, WSAPROTOCOL_INFOW *buffer, i
|
|||
|
||||
if (status)
|
||||
{
|
||||
set_error(status);
|
||||
unsigned int err = NtStatusToWSAError( status );
|
||||
SetLastError( err == WSAEBADF ? WSAENOTSOCK : err );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -5855,7 +5874,7 @@ SOCKET WINAPI WSASocketW(int af, int type, int protocol,
|
|||
|
||||
/* hack for WSADuplicateSocket */
|
||||
if (lpProtocolInfo && lpProtocolInfo->dwServiceFlags4 == 0xff00ff00) {
|
||||
ret = lpProtocolInfo->dwCatalogEntryId;
|
||||
ret = lpProtocolInfo->dwServiceFlags3;
|
||||
TRACE("\tgot duplicate %04lx\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -1968,6 +1968,167 @@ todo_wine
|
|||
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)
|
||||
{
|
||||
SOCKET v6 = INVALID_SOCKET;
|
||||
|
@ -6435,6 +6596,7 @@ START_TEST( sock )
|
|||
|
||||
test_getservbyname();
|
||||
test_WSASocket();
|
||||
test_WSADuplicateSocket();
|
||||
|
||||
test_WSAAddressToStringA();
|
||||
test_WSAAddressToStringW();
|
||||
|
|
Loading…
Reference in New Issue