Win32 SD_RECEIVE has the following effects on a TCP or UDP socket:
* further calls to recv() et al. fail with ESHUTDOWN. However, Linux and Mac instead return 0.
* currently pending calls to recv() are not affected. However, Linux and Mac cause them to return 0.
* calls to WSAPoll() are unaffected. However, Linux and Mac instead signal both POLLHUP and POLLIN.
* for TCP connections, further data sent by the peer causes the connection to be reset. Mac and BSD will silently drop data, and Linux simply queues it forever.
In short, SHUT_RD does nothing that we want it to do on Linux or Mac (and probably also BSD, though I am unable to test this).
Most of this impedance mismatch can be worked around in Wine, except for WSAPoll(). Since poll() will always return POLLHUP, we can't safely ask for POLLOUT, which we may need to do. Hence, since we aren't getting any benefit from SHUT_RD, don't use it.
Note that this doesn't actually fix any tests, since we have some rather bizarre logic to defer shutdown anyway (for an asynchronous socket, we don't call shutdown(SHUT_RD) until the peer sends data; this is probably an unintended bug, but "fixing" it ends up causing test failures, which is the main impetus for this patch.)
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 889f0327baf..aad92d5d4df 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -2290,7 +2290,7 @@ static NTSTATUS WS2_async_shutdown( void *user, IO_STATUS_BLOCK *iosb, NTSTATUS
switch ( wsa->type ) { - case ASYNC_TYPE_READ: err = shutdown( fd, 0 ); break; + case ASYNC_TYPE_READ: break; case ASYNC_TYPE_WRITE: err = shutdown( fd, 1 ); break; } status = err ? wsaErrStatus() : STATUS_SUCCESS; @@ -5550,7 +5550,7 @@ int WINAPI WS_shutdown(SOCKET s, int how) } else /* non-overlapped mode */ { - if ( shutdown( fd, how ) ) + if (how != SD_RECEIVE && shutdown( fd, SHUT_WR )) { err = wsaErrno(); goto error;
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- include/wine/afd.h | 1 + server/sock.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+)
diff --git a/include/wine/afd.h b/include/wine/afd.h index b085981b6c0..30429b02324 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -37,6 +37,7 @@ struct afd_listen_params #define IOCTL_AFD_WINE_ACCEPT CTL_CODE(FILE_DEVICE_NETWORK, 201, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_AFD_WINE_ACCEPT_INTO CTL_CODE(FILE_DEVICE_NETWORK, 202, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_AFD_WINE_CONNECT CTL_CODE(FILE_DEVICE_NETWORK, 203, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_AFD_WINE_SHUTDOWN CTL_CODE(FILE_DEVICE_NETWORK, 204, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_AFD_WINE_ADDRESS_LIST_CHANGE CTL_CODE(FILE_DEVICE_NETWORK, 323, METHOD_BUFFERED, FILE_ANY_ACCESS)
diff --git a/server/sock.c b/server/sock.c index 9896810def1..b523e8db780 100644 --- a/server/sock.c +++ b/server/sock.c @@ -135,6 +135,7 @@ struct sock unsigned int reported_events; unsigned int flags; /* socket flags */ int polling; /* is socket being polled? */ + int wr_shutdown_pending; /* is a write shutdown pending? */ unsigned short proto; /* socket protocol */ unsigned short type; /* socket type */ unsigned short family; /* socket family */ @@ -912,6 +913,9 @@ static void sock_reselect_async( struct fd *fd, struct async_queue *queue ) { struct sock *sock = get_fd_user( fd );
+ if (sock->wr_shutdown_pending && list_empty( &sock->write_q.queue )) + shutdown( get_unix_fd( sock->fd ), SHUT_WR ); + /* Don't reselect the ifchange queue; we always ask for POLLIN. * Don't reselect an uninitialized socket; we can't call set_fd_events() on * a pseudo-fd. */ @@ -983,6 +987,7 @@ static struct sock *create_socket(void) sock->pending_events = 0; sock->reported_events = 0; sock->polling = 0; + sock->wr_shutdown_pending = 0; sock->flags = 0; sock->proto = 0; sock->type = 0; @@ -1638,6 +1643,55 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) return 1; }
+ case IOCTL_AFD_WINE_SHUTDOWN: + { + unsigned int how; + + if (get_req_data_size() < sizeof(int)) + { + set_error( STATUS_BUFFER_TOO_SMALL ); + return 0; + } + how = *(int *)get_req_data(); + + if (how > SD_BOTH) + { + set_error( STATUS_INVALID_PARAMETER ); + return 0; + } + + if (sock->type == WS_SOCK_STREAM && !(sock->state & FD_WINE_CONNECTED)) + { + set_error( STATUS_INVALID_CONNECTION ); + return 0; + } + + if (how != SD_SEND) + { + sock->state &= ~FD_READ; + } + if (how != SD_RECEIVE) + { + sock->state &= ~FD_WRITE; + if (list_empty( &sock->write_q.queue )) + shutdown( unix_fd, SHUT_WR ); + else + sock->wr_shutdown_pending = 1; + } + + if (how == SD_BOTH) + { + if (sock->event) release_object( sock->event ); + sock->event = NULL; + sock->window = 0; + sock->mask = 0; + sock->state |= FD_WINE_NONBLOCKING; + } + + sock_reselect( sock ); + return 1; + } + case IOCTL_AFD_WINE_ADDRESS_LIST_CHANGE: if ((sock->state & FD_WINE_NONBLOCKING) && async_is_blocking( async )) {
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/socket.c | 29 ++++++++++++------ dlls/ws2_32/tests/sock.c | 65 ++++++++++++++++++---------------------- 2 files changed, 49 insertions(+), 45 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index aad92d5d4df..0110d53ab48 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -3110,23 +3110,34 @@ static BOOL WINAPI WS2_ConnectEx( SOCKET s, const struct WS_sockaddr *name, int return !status; }
-/*********************************************************************** - * DisconnectEx - */ -static BOOL WINAPI WS2_DisconnectEx( SOCKET s, LPOVERLAPPED ov, DWORD flags, DWORD reserved ) + +static BOOL WINAPI WS2_DisconnectEx( SOCKET s, OVERLAPPED *overlapped, DWORD flags, DWORD reserved ) { - TRACE( "socket %04lx, ov %p, flags 0x%x, reserved 0x%x\n", s, ov, flags, reserved ); + IO_STATUS_BLOCK iosb, *piosb = &iosb; + void *cvalue = NULL; + int how = SD_SEND; + HANDLE event = 0; + NTSTATUS status; + + TRACE( "socket %#lx, overlapped %p, flags %#x, reserved %#x\n", s, overlapped, flags, reserved );
if (flags & TF_REUSE_SOCKET) FIXME( "Reusing socket not supported yet\n" );
- if (ov) + if (overlapped) { - ov->Internal = STATUS_PENDING; - ov->InternalHigh = 0; + piosb = (IO_STATUS_BLOCK *)overlapped; + if (!((ULONG_PTR)overlapped->hEvent & 1)) cvalue = overlapped; + event = overlapped->hEvent; + overlapped->Internal = STATUS_PENDING; + overlapped->InternalHigh = 0; }
- return !WS_shutdown( s, SD_BOTH ); + status = NtDeviceIoControlFile( (HANDLE)s, event, NULL, cvalue, piosb, + IOCTL_AFD_WINE_SHUTDOWN, &how, sizeof(how), NULL, 0 ); + if (!status && overlapped) status = STATUS_PENDING; + SetLastError( NtStatusToWSAError( status ) ); + return !status; }
/*********************************************************************** diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 5028a4e749e..2c1f0e6142a 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -6732,7 +6732,7 @@ static void test_DisconnectEx(void) WSASetLastError(0xdeadbeef); ret = pDisconnectEx(client, &overlapped, 0, 0); ok(!ret, "expected failure\n"); - todo_wine ok(WSAGetLastError() == WSAENOTCONN, "got error %u\n", WSAGetLastError()); + ok(WSAGetLastError() == WSAENOTCONN, "got error %u\n", WSAGetLastError());
ret = connect(client, (struct sockaddr *)&server_addr, sizeof(server_addr)); ok(!ret, "failed to connect, error %u\n", WSAGetLastError()); @@ -6741,18 +6741,15 @@ static void test_DisconnectEx(void)
WSASetLastError(0xdeadbeef); ret = pDisconnectEx(client, &overlapped, 0, 0); - todo_wine ok(!ret, "expected failure\n"); - todo_wine ok(WSAGetLastError() == ERROR_IO_PENDING, "got error %u\n", WSAGetLastError()); + ok(!ret, "expected failure\n"); + ok(WSAGetLastError() == ERROR_IO_PENDING, "got error %u\n", WSAGetLastError());
- if (WSAGetLastError() == ERROR_IO_PENDING) - { - ret = WaitForSingleObject(overlapped.hEvent, 1000); - ok(!ret, "wait timed out\n"); - size = 0xdeadbeef; - ret = GetOverlappedResult((HANDLE)client, &overlapped, &size, FALSE); - ok(ret, "got error %u\n", GetLastError()); - ok(!size, "got size %u\n", size); - } + ret = WaitForSingleObject(overlapped.hEvent, 1000); + ok(!ret, "wait timed out\n"); + size = 0xdeadbeef; + ret = GetOverlappedResult((HANDLE)client, &overlapped, &size, FALSE); + ok(ret, "got error %u\n", GetLastError()); + ok(!size, "got size %u\n", size);
ret = connect(client, (struct sockaddr *)&server_addr, sizeof(server_addr)); ok(ret == -1, "expected failure\n"); @@ -6805,8 +6802,8 @@ static void test_DisconnectEx(void)
WSASetLastError(0xdeadbeef); ret = pDisconnectEx(client, NULL, 0, 0); - todo_wine ok(ret, "expected success\n"); - todo_wine ok(!WSAGetLastError() || WSAGetLastError() == 0xdeadbeef /* < 7 */, "got error %u\n", WSAGetLastError()); + ok(ret, "expected success\n"); + ok(!WSAGetLastError() || WSAGetLastError() == 0xdeadbeef /* < 7 */, "got error %u\n", WSAGetLastError());
ret = connect(client, (struct sockaddr *)&server_addr, sizeof(server_addr)); ok(ret == -1, "expected failure\n"); @@ -8552,18 +8549,16 @@ static void test_shutdown_completion_port(void)
SetLastError(0xdeadbeef); ret = pDisconnectEx(client, &overlapped, 0, 0); - todo_wine ok(!ret, "expected failure\n"); - todo_wine ok(GetLastError() == ERROR_IO_PENDING, "got error %u\n", GetLastError()); - if (GetLastError() == ERROR_IO_PENDING) - { - ret = WaitForSingleObject(overlapped.hEvent, 1000); - ok(!ret, "wait failed\n"); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_IO_PENDING, "got error %u\n", GetLastError());
- size = 0xdeadbeef; - ret = GetOverlappedResult((HANDLE)client, &overlapped, &size, TRUE); - ok(ret, "got error %u\n", GetLastError()); - ok(!size, "got %u bytes\n", size); - } + ret = WaitForSingleObject(overlapped.hEvent, 1000); + ok(!ret, "wait failed\n"); + + size = 0xdeadbeef; + ret = GetOverlappedResult((HANDLE)client, &overlapped, &size, TRUE); + ok(ret, "got error %u\n", GetLastError()); + ok(!size, "got %u bytes\n", size);
size = 0xdeadbeef; key = 0xdeadbeef; @@ -8617,18 +8612,16 @@ static void test_shutdown_completion_port(void)
SetLastError(0xdeadbeef); ret = pDisconnectEx(client, &overlapped, 0, 0); - todo_wine ok(!ret, "expected failure\n"); - todo_wine ok(GetLastError() == ERROR_IO_PENDING, "got error %u\n", GetLastError()); - if (GetLastError() == ERROR_IO_PENDING) - { - ret = WaitForSingleObject(overlapped.hEvent, 1000); - ok(!ret, "wait failed\n"); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_IO_PENDING, "got error %u\n", GetLastError());
- size = 0xdeadbeef; - ret = GetOverlappedResult((HANDLE)client, &overlapped, &size, TRUE); - ok(ret, "got error %u\n", GetLastError()); - ok(!size, "got %u bytes\n", size); - } + ret = WaitForSingleObject(overlapped.hEvent, 1000); + ok(!ret, "wait failed\n"); + + size = 0xdeadbeef; + ret = GetOverlappedResult((HANDLE)client, &overlapped, &size, TRUE); + ok(ret, "got error %u\n", GetLastError()); + ok(!size, "got %u bytes\n", size);
ret = GetQueuedCompletionStatus(port, &size, &key, &overlapped_ptr, 0); ok(!ret, "expected failure\n");
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/socket.c | 130 ++++----------------------------------- dlls/ws2_32/tests/sock.c | 20 +++--- 2 files changed, 21 insertions(+), 129 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 0110d53ab48..3632397ef3d 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -2272,64 +2272,6 @@ static NTSTATUS WS2_async_send( void *user, IO_STATUS_BLOCK *iosb, NTSTATUS stat return status; }
-/*********************************************************************** - * WS2_async_shutdown (INTERNAL) - * - * Handler for shutdown() operations on overlapped sockets. - */ -static NTSTATUS WS2_async_shutdown( void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status ) -{ - struct ws2_async_shutdown *wsa = user; - int fd, err = 1; - - switch (status) - { - case STATUS_ALERTED: - if ((status = wine_server_handle_to_fd( wsa->hSocket, 0, &fd, NULL ) )) - break; - - switch ( wsa->type ) - { - case ASYNC_TYPE_READ: break; - case ASYNC_TYPE_WRITE: err = shutdown( fd, 1 ); break; - } - status = err ? wsaErrStatus() : STATUS_SUCCESS; - close( fd ); - break; - } - iosb->u.Status = status; - iosb->Information = 0; - release_async_io( &wsa->io ); - return status; -} - -/*********************************************************************** - * WS2_register_async_shutdown (INTERNAL) - * - * Helper function for WS_shutdown() on overlapped sockets. - */ -static int WS2_register_async_shutdown( SOCKET s, int type ) -{ - struct ws2_async_shutdown *wsa; - NTSTATUS status; - - TRACE("socket %04lx type %d\n", s, type); - - wsa = (struct ws2_async_shutdown *)alloc_async_io( sizeof(*wsa), WS2_async_shutdown ); - if ( !wsa ) - return WSAEFAULT; - - wsa->hSocket = SOCKET2HANDLE(s); - wsa->type = type; - - status = register_async( type, wsa->hSocket, &wsa->io, 0, NULL, NULL, &wsa->iosb ); - if (status != STATUS_PENDING) - { - HeapFree( GetProcessHeap(), 0, wsa ); - return NtStatusToWSAError( status ); - } - return 0; -}
/*********************************************************************** * accept (WS2_32.1) @@ -5512,74 +5454,24 @@ int WINAPI WS_setsockopt(SOCKET s, int level, int optname, return SOCKET_ERROR; }
+ /*********************************************************************** - * shutdown (WS2_32.22) + * shutdown (ws2_32.22) */ -int WINAPI WS_shutdown(SOCKET s, int how) +int WINAPI WS_shutdown( SOCKET s, int how ) { - int fd, err = WSAENOTSOCK; - unsigned int options = 0, clear_flags = 0; + IO_STATUS_BLOCK io; + NTSTATUS status;
- fd = get_sock_fd( s, 0, &options ); - TRACE("socket %04lx, how 0x%x, options 0x%x\n", s, how, options ); + TRACE( "socket %#lx, how %u\n", s, how );
- if (fd == -1) - return SOCKET_ERROR; - - switch( how ) - { - case SD_RECEIVE: /* drop receives */ - clear_flags |= FD_READ; - break; - case SD_SEND: /* drop sends */ - clear_flags |= FD_WRITE; - break; - case SD_BOTH: /* drop all */ - clear_flags |= FD_READ|FD_WRITE; - /*fall through */ - default: - clear_flags |= FD_WINE_LISTENING; - } - - if (!(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))) - { - switch ( how ) - { - case SD_RECEIVE: - err = WS2_register_async_shutdown( s, ASYNC_TYPE_READ ); - break; - case SD_SEND: - err = WS2_register_async_shutdown( s, ASYNC_TYPE_WRITE ); - break; - case SD_BOTH: - default: - err = WS2_register_async_shutdown( s, ASYNC_TYPE_READ ); - if (!err) err = WS2_register_async_shutdown( s, ASYNC_TYPE_WRITE ); - break; - } - if (err) goto error; - } - else /* non-overlapped mode */ - { - if (how != SD_RECEIVE && shutdown( fd, SHUT_WR )) - { - err = wsaErrno(); - goto error; - } - } - - release_sock_fd( s, fd ); - _enable_event( SOCKET2HANDLE(s), 0, 0, clear_flags ); - if ( how > 1) WSAAsyncSelect( s, 0, 0, 0 ); - return 0; - -error: - release_sock_fd( s, fd ); - _enable_event( SOCKET2HANDLE(s), 0, 0, clear_flags ); - SetLastError( err ); - return SOCKET_ERROR; + status = NtDeviceIoControlFile( (HANDLE)s, NULL, NULL, NULL, &io, + IOCTL_AFD_WINE_SHUTDOWN, &how, sizeof(how), NULL, 0 ); + SetLastError( NtStatusToWSAError( status ) ); + return status ? -1 : 0; }
+ /*********************************************************************** * socket (WS2_32.23) */ diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 2c1f0e6142a..8bec781ac6f 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -6405,12 +6405,12 @@ static void test_shutdown(void) WSASetLastError(0xdeadbeef); ret = shutdown(client, SD_SEND); ok(ret == -1, "expected failure\n"); - todo_wine ok(WSAGetLastError() == WSAENOTCONN, "got error %u\n", WSAGetLastError()); + ok(WSAGetLastError() == WSAENOTCONN, "got error %u\n", WSAGetLastError());
WSASetLastError(0xdeadbeef); ret = shutdown(client, SD_RECEIVE); ok(ret == -1, "expected failure\n"); - todo_wine ok(WSAGetLastError() == WSAENOTCONN, "got error %u\n", WSAGetLastError()); + ok(WSAGetLastError() == WSAENOTCONN, "got error %u\n", WSAGetLastError());
ret = connect(client, (struct sockaddr *)&server_addr, sizeof(server_addr)); ok(!ret, "failed to connect, error %u\n", WSAGetLastError()); @@ -6425,8 +6425,8 @@ static void test_shutdown(void)
WSASetLastError(0xdeadbeef); ret = shutdown(client, SD_SEND); - todo_wine ok(!ret, "expected success\n"); - todo_wine ok(!WSAGetLastError() || WSAGetLastError() == 0xdeadbeef /* < 7 */, "got error %u\n", WSAGetLastError()); + ok(!ret, "expected success\n"); + ok(!WSAGetLastError() || WSAGetLastError() == 0xdeadbeef /* < 7 */, "got error %u\n", WSAGetLastError());
WSASetLastError(0xdeadbeef); ret = send(client, "test", 5, 0); @@ -6501,7 +6501,7 @@ static void test_shutdown(void) WSASetLastError(0xdeadbeef); ret = shutdown(client, 0xdeadbeef); ok(ret == -1, "expected failure\n"); - todo_wine ok(WSAGetLastError() == WSAEINVAL, "got error %u\n", WSAGetLastError()); + ok(WSAGetLastError() == WSAEINVAL, "got error %u\n", WSAGetLastError());
closesocket(client); closesocket(server); @@ -6628,12 +6628,12 @@ static void test_shutdown(void) WSASetLastError(0xdeadbeef); ret = shutdown(listener, SD_SEND); ok(ret == -1, "expected failure\n"); - todo_wine ok(WSAGetLastError() == WSAENOTCONN, "got error %u\n", WSAGetLastError()); + ok(WSAGetLastError() == WSAENOTCONN, "got error %u\n", WSAGetLastError());
WSASetLastError(0xdeadbeef); ret = shutdown(listener, SD_RECEIVE); - todo_wine ok(ret == -1, "expected failure\n"); - todo_wine ok(WSAGetLastError() == WSAENOTCONN, "got error %u\n", WSAGetLastError()); + ok(ret == -1, "expected failure\n"); + ok(WSAGetLastError() == WSAENOTCONN, "got error %u\n", WSAGetLastError());
closesocket(listener);
@@ -6671,8 +6671,8 @@ static void test_shutdown(void)
WSASetLastError(0xdeadbeef); ret = shutdown(client, SD_SEND); - todo_wine ok(!ret, "expected success\n"); - todo_wine ok(!WSAGetLastError() || WSAGetLastError() == 0xdeadbeef /* < 7 */, "got error %u\n", WSAGetLastError()); + ok(!ret, "expected success\n"); + ok(!WSAGetLastError() || WSAGetLastError() == 0xdeadbeef /* < 7 */, "got error %u\n", WSAGetLastError());
WSASetLastError(0xdeadbeef); ret = sendto(client, "test", 5, 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/tests/sock.c | 63 +++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 8 deletions(-)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 8bec781ac6f..f390fb79640 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -1769,6 +1769,16 @@ static void test_so_reuseaddr(void)
#define IP_PKTINFO_LEN (sizeof(WSACMSGHDR) + WSA_CMSG_ALIGN(sizeof(struct in_pktinfo)))
+static unsigned int got_ip_pktinfo_apc; + +static void WINAPI ip_pktinfo_apc(DWORD error, DWORD size, OVERLAPPED *overlapped, DWORD flags) +{ + ok(error == WSAEMSGSIZE, "got error %u\n", error); + ok(size == 6, "got size %u\n", size); + ok(!flags, "got flags %#x\n", flags); + ++got_ip_pktinfo_apc; +} + static void test_ip_pktinfo(void) { ULONG addresses[2] = {inet_addr("127.0.0.1"), htonl(INADDR_ANY)}; @@ -1858,14 +1868,20 @@ static void test_ip_pktinfo(void) ok(rc == sizeof(msg), "sendto() failed error: %d\n", WSAGetLastError()); ok(GetLastError() == ERROR_SUCCESS, "Expected 0, got %d\n", GetLastError()); hdr.Control.len = 1; - rc=pWSARecvMsg(s1, &hdr, &dwSize, NULL, NULL); - err=WSAGetLastError(); - ok(rc == SOCKET_ERROR && err == WSAEMSGSIZE && (hdr.dwFlags & MSG_CTRUNC), - "WSARecvMsg() failed error: %d (ret: %d, flags: %d)\n", err, rc, hdr.dwFlags); + dwSize = 0xdeadbeef; + rc = pWSARecvMsg(s1, &hdr, &dwSize, NULL, NULL); + ok(rc == -1, "expected failure\n"); + ok(WSAGetLastError() == WSAEMSGSIZE, "got error %u\n", WSAGetLastError()); + todo_wine ok(dwSize == sizeof(msg), "got size %u\n", dwSize); + ok(hdr.dwFlags == MSG_CTRUNC, "got flags %#x\n", hdr.dwFlags); hdr.dwFlags = 0; /* Reset flags */
/* Perform another short control header test, this time with an overlapped receive */ hdr.Control.len = 1; + ov.Internal = 0xdead1; + ov.InternalHigh = 0xdead2; + ov.Offset = 0xdead3; + ov.OffsetHigh = 0xdead4; rc=pWSARecvMsg(s1, &hdr, NULL, &ov, NULL); err=WSAGetLastError(); ok(rc != 0 && err == WSA_IO_PENDING, "WSARecvMsg() failed error: %d\n", err); @@ -1874,14 +1890,45 @@ static void test_ip_pktinfo(void) ok(rc == sizeof(msg), "sendto() failed error: %d\n", WSAGetLastError()); ok(GetLastError() == ERROR_SUCCESS, "Expected 0, got %d\n", GetLastError()); ok(!WaitForSingleObject(ov.hEvent, 100), "wait failed\n"); - dwFlags = 0; - WSAGetOverlappedResult(s1, &ov, NULL, FALSE, &dwFlags); - ok(dwFlags == 0, - "WSAGetOverlappedResult() returned unexpected flags %d!\n", dwFlags); + ok((NTSTATUS)ov.Internal == STATUS_BUFFER_OVERFLOW, "got status %#x\n", (NTSTATUS)ov.Internal); + todo_wine ok(ov.InternalHigh == sizeof(msg), "got size %Iu\n", ov.InternalHigh); + ok(ov.Offset == 0xdead3, "got Offset %Iu\n", ov.Offset); + ok(ov.OffsetHigh == 0xdead4, "got OffsetHigh %Iu\n", ov.OffsetHigh); + dwFlags = 0xdeadbeef; + rc = WSAGetOverlappedResult(s1, &ov, &dwSize, FALSE, &dwFlags); + ok(!rc, "expected failure\n"); + ok(WSAGetLastError() == WSAEMSGSIZE, "got error %u\n", WSAGetLastError()); + todo_wine ok(dwSize == sizeof(msg), "got size %u\n", dwSize); + todo_wine ok(dwFlags == 0xdeadbeef, "got flags %#x\n", dwFlags); ok(hdr.dwFlags == MSG_CTRUNC, "WSARecvMsg() overlapped operation set unexpected flags %d.\n", hdr.dwFlags); hdr.dwFlags = 0; /* Reset flags */
+ /* And with an APC. */ + + SetLastError(0xdeadbeef); + rc = sendto(s2, msg, sizeof(msg), 0, (struct sockaddr *)&s2addr, sizeof(s2addr)); + ok(rc == sizeof(msg), "sendto() failed error: %d\n", WSAGetLastError()); + ok(GetLastError() == ERROR_SUCCESS, "Expected 0, got %d\n", GetLastError()); + hdr.Control.len = 1; + + ov.Internal = 0xdead1; + ov.InternalHigh = 0xdead2; + ov.Offset = 0xdead3; + ov.OffsetHigh = 0xdead4; + dwSize = 0xdeadbeef; + rc = pWSARecvMsg(s1, &hdr, NULL, &ov, ip_pktinfo_apc); + ok(rc == -1, "expected failure\n"); + todo_wine ok(WSAGetLastError() == ERROR_IO_PENDING, "got error %u\n", WSAGetLastError()); + + rc = SleepEx(0, TRUE); + todo_wine ok(rc == WAIT_IO_COMPLETION, "got %d\n", rc); + todo_wine ok(got_ip_pktinfo_apc == 1, "apc was called %u times\n", got_ip_pktinfo_apc); + ok(hdr.dwFlags == MSG_CTRUNC, "got flags %#x\n", hdr.dwFlags); + got_ip_pktinfo_apc = 0; + + hdr.dwFlags = 0; /* Reset flags */ + /* * Setup an overlapped receive, send a packet, then wait for the packet to be retrieved * on the server end and check that the returned packet matches what was sent.
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=90763
Your paranoid android.
=== wvistau64 (64 bit report) ===
ws2_32: sock.c:1925: Test failed: got 0 sock.c:1926: Test failed: apc was called 0 times sock.c:1776: Test failed: got error 0 sock.c:1925: Test failed: got 0 sock.c:1776: Test failed: got error 0 sock.c:1777: Test failed: got size 0
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/tests/sock.c | 75 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index f390fb79640..46cd2d8ace4 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -9926,6 +9926,80 @@ static void test_empty_recv(void) CloseHandle(overlapped.hEvent); }
+static void test_timeout(void) +{ + DWORD timeout, flags = 0, size; + OVERLAPPED overlapped = {0}; + SOCKET client, server; + WSABUF wsabuf; + int ret, len; + char buffer; + + tcp_socketpair(&client, &server); + overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + + timeout = 0xdeadbeef; + len = sizeof(timeout); + WSASetLastError(0xdeadbeef); + ret = getsockopt(client, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, &len); + ok(!ret, "expected success\n"); + todo_wine ok(!WSAGetLastError(), "got error %u\n", WSAGetLastError()); + ok(len == sizeof(timeout), "got size %u\n", len); + ok(!timeout, "got timeout %u\n", timeout); + + timeout = 100; + WSASetLastError(0xdeadbeef); + ret = setsockopt(client, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); + ok(!ret, "expected success\n"); + todo_wine ok(!WSAGetLastError(), "got error %u\n", WSAGetLastError()); + + timeout = 0xdeadbeef; + len = sizeof(timeout); + WSASetLastError(0xdeadbeef); + ret = getsockopt(client, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, &len); + ok(!ret, "expected success\n"); + todo_wine ok(!WSAGetLastError(), "got error %u\n", WSAGetLastError()); + todo_wine ok(timeout == 100, "got timeout %u\n", timeout); + + WSASetLastError(0xdeadbeef); + ret = recv(client, &buffer, 1, 0); + ok(ret == -1, "got %d\n", ret); + ok(WSAGetLastError() == WSAETIMEDOUT, "got error %u\n", WSAGetLastError()); + + wsabuf.buf = &buffer; + wsabuf.len = 1; + WSASetLastError(0xdeadbeef); + size = 0xdeadbeef; + ret = WSARecv(client, &wsabuf, 1, &size, &flags, NULL, NULL); + ok(ret == -1, "got %d\n", ret); + ok(WSAGetLastError() == WSAETIMEDOUT, "got error %u\n", WSAGetLastError()); + ok(size == 0xdeadbeef, "got size %u\n", size); + + wsabuf.buf = &buffer; + wsabuf.len = 1; + WSASetLastError(0xdeadbeef); + size = 0xdeadbeef; + ret = WSARecv(client, &wsabuf, 1, &size, &flags, &overlapped, NULL); + ok(ret == -1, "got %d\n", ret); + ok(WSAGetLastError() == ERROR_IO_PENDING, "got error %u\n", WSAGetLastError()); + + ret = WaitForSingleObject(overlapped.hEvent, 200); + ok(ret == WAIT_TIMEOUT, "got %d\n", ret); + + ret = send(server, "a", 1, 0); + ok(ret == 1, "got %d\n", ret); + + ret = WaitForSingleObject(overlapped.hEvent, 200); + ok(!ret, "got %d\n", ret); + ret = GetOverlappedResult((HANDLE)client, &overlapped, &size, FALSE); + ok(ret, "got error %u\n", GetLastError()); + ok(size == 1, "got size %u\n", size); + + closesocket(client); + closesocket(server); + CloseHandle(overlapped.hEvent); +} + START_TEST( sock ) { int i; @@ -9987,6 +10061,7 @@ START_TEST( sock ) test_WSAGetOverlappedResult(); test_nonblocking_async_recv(); test_empty_recv(); + test_timeout();
/* this is an io heavy test, do it at the end so the kernel doesn't start dropping packets */ test_send();
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=90764
Your paranoid android.
=== wvistau64 (64 bit report) ===
ws2_32: sock.c:1925: Test failed: got 0 sock.c:1926: Test failed: apc was called 0 times sock.c:1776: Test failed: got error 0 sock.c:1925: Test failed: got 0 sock.c:1776: Test failed: got error 0 sock.c:1777: Test failed: got size 0