ws2_32: Fix WSADuplicateSocket implementation
Bruno Jesus
00cpxxx at gmail.com
Wed Sep 11 08:05:18 CDT 2013
This patch superseeds 98606, 98609, 98610.
Fixes bug 32412.
Clean run: https://testbot.winehq.org/JobDetails.pl?Key=27024
-------------- next part --------------
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 5f5f161..eacc793 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -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;
}
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index e072033..f4978d1 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -1968,6 +1968,170 @@ 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), "expected %d bytes sent, %d (err %d)\n",
+ sizeof(teststr), 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), "expected %d bytes received, %d (err %d)\n",
+ sizeof(teststr), 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), "expected %d bytes sent, %d (err %d)\n",
+ sizeof(teststr), 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 +6599,7 @@ START_TEST( sock )
test_getservbyname();
test_WSASocket();
+ test_WSADuplicateSocket();
test_WSAAddressToStringA();
test_WSAAddressToStringW();
More information about the wine-patches
mailing list