ws2_32: Fix WSADuplicateSocket implementation.

This commit is contained in:
Bruno Jesus 2013-09-11 10:05:18 -03:00 committed by Alexandre Julliard
parent 31f8893678
commit d71bf64e87
2 changed files with 187 additions and 6 deletions

View File

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

View File

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