Signed-off-by: Zebediah Figura z.figura12@gmail.com --- include/wine/afd.h | 1 + server/sock.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+)
diff --git a/include/wine/afd.h b/include/wine/afd.h index ae5a0584bdc..99df0b8d65e 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -169,6 +169,7 @@ struct afd_get_events_params #define IOCTL_AFD_WINE_SET_SO_LINGER CTL_CODE(FILE_DEVICE_NETWORK, 226, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_AFD_WINE_GET_SO_OOBINLINE CTL_CODE(FILE_DEVICE_NETWORK, 227, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_AFD_WINE_SET_SO_OOBINLINE CTL_CODE(FILE_DEVICE_NETWORK, 228, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_AFD_WINE_SET_SO_RCVBUF CTL_CODE(FILE_DEVICE_NETWORK, 229, METHOD_BUFFERED, FILE_ANY_ACCESS)
struct afd_create_params { diff --git a/server/sock.c b/server/sock.c index e7754dc0da3..aaac693d098 100644 --- a/server/sock.c +++ b/server/sock.c @@ -2580,6 +2580,22 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) return 1; }
+ case IOCTL_AFD_WINE_SET_SO_RCVBUF: + { + DWORD rcvbuf; + + if (get_req_data_size() < sizeof(rcvbuf)) + { + set_error( STATUS_BUFFER_TOO_SMALL ); + return 0; + } + rcvbuf = *(DWORD *)get_req_data(); + + if (setsockopt( unix_fd, SOL_SOCKET, SO_RCVBUF, (char *)&rcvbuf, sizeof(rcvbuf) ) < 0) + set_error( sock_get_ntstatus( errno ) ); + return 0; + } + default: set_error( STATUS_NOT_SUPPORTED ); return 0;
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- include/wine/afd.h | 1 + server/sock.c | 27 +++++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/include/wine/afd.h b/include/wine/afd.h index 99df0b8d65e..0692394459e 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -170,6 +170,7 @@ struct afd_get_events_params #define IOCTL_AFD_WINE_GET_SO_OOBINLINE CTL_CODE(FILE_DEVICE_NETWORK, 227, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_AFD_WINE_SET_SO_OOBINLINE CTL_CODE(FILE_DEVICE_NETWORK, 228, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_AFD_WINE_SET_SO_RCVBUF CTL_CODE(FILE_DEVICE_NETWORK, 229, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_AFD_WINE_GET_SO_RCVBUF CTL_CODE(FILE_DEVICE_NETWORK, 230, METHOD_BUFFERED, FILE_ANY_ACCESS)
struct afd_create_params { diff --git a/server/sock.c b/server/sock.c index aaac693d098..8bad31efdd1 100644 --- a/server/sock.c +++ b/server/sock.c @@ -207,6 +207,7 @@ struct sock struct connect_req *connect_req; /* pending connection request */ union win_sockaddr addr; /* socket name */ int addr_len; /* socket name length */ + unsigned int rcvbuf; /* advisory recv buffer size */ unsigned int rd_shutdown : 1; /* is the read end shut down? */ unsigned int wr_shutdown : 1; /* is the write end shut down? */ unsigned int wr_shutdown_pending : 1; /* is a write shutdown pending? */ @@ -1386,6 +1387,7 @@ static struct sock *create_socket(void) sock->wr_shutdown_pending = 0; sock->nonblocking = 0; sock->bound = 0; + sock->rcvbuf = 0; init_async_queue( &sock->read_q ); init_async_queue( &sock->write_q ); init_async_queue( &sock->ifchange_q ); @@ -1477,7 +1479,8 @@ static void set_dont_fragment( int fd, int level, int value ) static int init_socket( struct sock *sock, int family, int type, int protocol, unsigned int flags ) { unsigned int options = 0; - int sockfd, unix_type, unix_family, unix_protocol; + int sockfd, unix_type, unix_family, unix_protocol, value; + socklen_t len;
unix_family = get_unix_family( family ); unix_type = get_unix_type( type ); @@ -1543,6 +1546,10 @@ static int init_socket( struct sock *sock, int family, int type, int protocol, u } #endif
+ len = sizeof(value); + if (!getsockopt( sockfd, SOL_SOCKET, SO_RCVBUF, &value, &len )) + sock->rcvbuf = value; + sock->state = (type == WS_SOCK_STREAM ? SOCK_UNCONNECTED : SOCK_CONNECTIONLESS); sock->flags = flags; sock->proto = protocol; @@ -2580,6 +2587,20 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) return 1; }
+ case IOCTL_AFD_WINE_GET_SO_RCVBUF: + { + int rcvbuf = sock->rcvbuf; + + if (get_reply_max_size() < sizeof(rcvbuf)) + { + set_error( STATUS_BUFFER_TOO_SMALL ); + return 0; + } + + set_reply_data( &rcvbuf, sizeof(rcvbuf) ); + return 1; + } + case IOCTL_AFD_WINE_SET_SO_RCVBUF: { DWORD rcvbuf; @@ -2591,7 +2612,9 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) } rcvbuf = *(DWORD *)get_req_data();
- if (setsockopt( unix_fd, SOL_SOCKET, SO_RCVBUF, (char *)&rcvbuf, sizeof(rcvbuf) ) < 0) + if (!setsockopt( unix_fd, SOL_SOCKET, SO_RCVBUF, (char *)&rcvbuf, sizeof(rcvbuf) )) + sock->rcvbuf = rcvbuf; + else set_error( sock_get_ntstatus( errno ) ); return 0; }
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/socket.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 88d8e9bf134..4982b08934b 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -3559,6 +3559,9 @@ int WINAPI WS_setsockopt(SOCKET s, int level, int optname, case WS_SO_OOBINLINE: return server_setsockopt( s, IOCTL_AFD_WINE_SET_SO_OOBINLINE, optval, optlen );
+ case WS_SO_RCVBUF: + return server_setsockopt( s, IOCTL_AFD_WINE_SET_SO_RCVBUF, optval, optlen ); + /* Some options need some conversion before they can be sent to * setsockopt. The conversions are done here, then they will fall through * to the general case. Special options that are not passed to @@ -3575,14 +3578,6 @@ int WINAPI WS_setsockopt(SOCKET s, int level, int optname, convert_sockopt(&level, &optname); break;
- case WS_SO_RCVBUF: - if (*(const int*)optval < 2048) - { - WARN("SO_RCVBF for %d bytes is too small: ignored\n", *(const int*)optval ); - return 0; - } - /* Fall through */ - /* The options listed here don't need any special handling. Thanks to * the conversion happening above, options from there will fall through * to this, too.*/
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/socket.c | 5 ++++- dlls/ws2_32/tests/sock.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 4982b08934b..7ed48124a5a 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -2090,7 +2090,6 @@ INT WINAPI WS_getsockopt(SOCKET s, INT level,
/* Handle common cases. The special cases are below, sorted * alphabetically */ - case WS_SO_RCVBUF: case WS_SO_REUSEADDR: case WS_SO_SNDBUF: if ( (fd = get_sock_fd( s, 0, NULL )) == -1) @@ -2285,6 +2284,10 @@ INT WINAPI WS_getsockopt(SOCKET s, INT level, } return ret ? 0 : SOCKET_ERROR; } + + case WS_SO_RCVBUF: + return server_getsockopt( s, IOCTL_AFD_WINE_GET_SO_RCVBUF, optval, optlen ); + case WS_SO_RCVTIMEO: case WS_SO_SNDTIMEO: { diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 9f461376853..ccaa04e4ef5 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -1224,7 +1224,7 @@ static void test_set_getsockopt(void) value = 0xdeadbeef; err = getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&value, &size); ok( !err, "getsockopt(SO_RCVBUF) failed error: %u\n", WSAGetLastError() ); - todo_wine ok( value == 4096, "expected 4096, got %u\n", value ); + ok( value == 4096, "expected 4096, got %u\n", value );
/* SO_LINGER */ for( i = 0; i < ARRAY_SIZE(linger_testvals);i++) {
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=93150
Your paranoid android.
=== debiant2 (32 bit Hindi:India report) ===
ws2_32: sock.c:8320: Test succeeded inside todo block: GetQueuedCompletionStatus returned 0 sock.c:8321: Test succeeded inside todo block: Last error was 64
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/socket.c | 10 +++++----- dlls/ws2_32/tests/sock.c | 8 ++++---- include/wine/afd.h | 2 ++ server/sock.c | 40 +++++++++++++++++++++++++++++++++------- 4 files changed, 44 insertions(+), 16 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 7ed48124a5a..15c9d0cc940 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -2289,6 +2289,8 @@ INT WINAPI WS_getsockopt(SOCKET s, INT level, return server_getsockopt( s, IOCTL_AFD_WINE_GET_SO_RCVBUF, optval, optlen );
case WS_SO_RCVTIMEO: + return server_getsockopt( s, IOCTL_AFD_WINE_GET_SO_RCVTIMEO, optval, optlen ); + case WS_SO_SNDTIMEO: { INT64 timeout; @@ -3565,6 +3567,9 @@ int WINAPI WS_setsockopt(SOCKET s, int level, int optname, case WS_SO_RCVBUF: return server_setsockopt( s, IOCTL_AFD_WINE_SET_SO_RCVBUF, optval, optlen );
+ case WS_SO_RCVTIMEO: + return server_setsockopt( s, IOCTL_AFD_WINE_SET_SO_RCVTIMEO, optval, optlen ); + /* Some options need some conversion before they can be sent to * setsockopt. The conversions are done here, then they will fall through * to the general case. Special options that are not passed to @@ -3631,13 +3636,8 @@ int WINAPI WS_setsockopt(SOCKET s, int level, int optname, TRACE("setting global SO_OPENTYPE = 0x%x\n", *((const int*)optval) ); return 0;
-#ifdef SO_RCVTIMEO - case WS_SO_RCVTIMEO: -#endif #ifdef SO_SNDTIMEO case WS_SO_SNDTIMEO: -#endif -#if defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO) if (optval && optlen == sizeof(UINT32)) { /* WinSock passes milliseconds instead of struct timeval */ tval.tv_usec = (*(const UINT32*)optval % 1000) * 1000; diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index ccaa04e4ef5..a3f7e002ce7 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -10919,7 +10919,7 @@ static void test_timeout(void) 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(!WSAGetLastError(), "got error %u\n", WSAGetLastError()); ok(len == sizeof(timeout), "got size %u\n", len); ok(!timeout, "got timeout %u\n", timeout);
@@ -10927,15 +10927,15 @@ static void test_timeout(void) 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()); + 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); + ok(!WSAGetLastError(), "got error %u\n", WSAGetLastError()); + ok(timeout == 100, "got timeout %u\n", timeout);
WSASetLastError(0xdeadbeef); ret = recv(client, &buffer, 1, 0); diff --git a/include/wine/afd.h b/include/wine/afd.h index 0692394459e..c4f7c7a6413 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -171,6 +171,8 @@ struct afd_get_events_params #define IOCTL_AFD_WINE_SET_SO_OOBINLINE CTL_CODE(FILE_DEVICE_NETWORK, 228, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_AFD_WINE_SET_SO_RCVBUF CTL_CODE(FILE_DEVICE_NETWORK, 229, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_AFD_WINE_GET_SO_RCVBUF CTL_CODE(FILE_DEVICE_NETWORK, 230, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_AFD_WINE_SET_SO_RCVTIMEO CTL_CODE(FILE_DEVICE_NETWORK, 231, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_AFD_WINE_GET_SO_RCVTIMEO CTL_CODE(FILE_DEVICE_NETWORK, 232, METHOD_BUFFERED, FILE_ANY_ACCESS)
struct afd_create_params { diff --git a/server/sock.c b/server/sock.c index 8bad31efdd1..d86b88b0564 100644 --- a/server/sock.c +++ b/server/sock.c @@ -208,6 +208,7 @@ struct sock union win_sockaddr addr; /* socket name */ int addr_len; /* socket name length */ unsigned int rcvbuf; /* advisory recv buffer size */ + unsigned int rcvtimeo; /* receive timeout in ms */ unsigned int rd_shutdown : 1; /* is the read end shut down? */ unsigned int wr_shutdown : 1; /* is the write end shut down? */ unsigned int wr_shutdown_pending : 1; /* is a write shutdown pending? */ @@ -1388,6 +1389,7 @@ static struct sock *create_socket(void) sock->nonblocking = 0; sock->bound = 0; sock->rcvbuf = 0; + sock->rcvtimeo = 0; init_async_queue( &sock->read_q ); init_async_queue( &sock->write_q ); init_async_queue( &sock->ifchange_q ); @@ -2619,6 +2621,35 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) return 0; }
+ case IOCTL_AFD_WINE_GET_SO_RCVTIMEO: + { + DWORD rcvtimeo = sock->rcvtimeo; + + if (get_reply_max_size() < sizeof(rcvtimeo)) + { + set_error( STATUS_BUFFER_TOO_SMALL ); + return 0; + } + + set_reply_data( &rcvtimeo, sizeof(rcvtimeo) ); + return 1; + } + + case IOCTL_AFD_WINE_SET_SO_RCVTIMEO: + { + DWORD rcvtimeo; + + if (get_req_data_size() < sizeof(rcvtimeo)) + { + set_error( STATUS_BUFFER_TOO_SMALL ); + return 0; + } + rcvtimeo = *(DWORD *)get_req_data(); + + sock->rcvtimeo = rcvtimeo; + return 0; + } + default: set_error( STATUS_NOT_SUPPORTED ); return 0; @@ -3029,19 +3060,14 @@ DECL_HANDLER(recv_socket) /* recv() returned EWOULDBLOCK, i.e. no data available yet */ if (status == STATUS_DEVICE_NOT_READY && !sock->nonblocking) { -#ifdef SO_RCVTIMEO - struct timeval tv; - socklen_t len = sizeof(tv); - /* Set a timeout on the async if necessary. * * We want to do this *only* if the client gave us STATUS_DEVICE_NOT_READY. * If the client gave us STATUS_PENDING, it expects the async to always * block (it was triggered by WSARecv*() with a valid OVERLAPPED * structure) and for the timeout not to be respected. */ - if (is_fd_overlapped( fd ) && !getsockopt( get_unix_fd( fd ), SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, &len )) - timeout = tv.tv_sec * -10000000 + tv.tv_usec * -10; -#endif + if (is_fd_overlapped( fd )) + timeout = sock->rcvtimeo * -10000;
status = STATUS_PENDING; }
Zebediah Figura z.figura12@gmail.com writes:
Signed-off-by: Zebediah Figura z.figura12@gmail.com
dlls/ws2_32/socket.c | 10 +++++----- dlls/ws2_32/tests/sock.c | 8 ++++---- include/wine/afd.h | 2 ++ server/sock.c | 40 +++++++++++++++++++++++++++++++++------- 4 files changed, 44 insertions(+), 16 deletions(-)
This is breaking tests:
tools/runtest -q -P wine -T . -M webservices.dll -p dlls/webservices/tests/webservices_test.exe proxy && touch dlls/webservices/tests/proxy.ok proxy.c:298: Test failed: got 8007274c proxy.c:327: Test failed: got 8007274c proxy.c:350: Test failed: got 803d0000 proxy.c:351: Test failed: got -1 proxy.c:614: Test failed: got 8007274c wine: Unhandled page fault on read access to 00000000 at address 6A2E848A (thread 0024), starting debugger... Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x6a2e848a). Register dump: CS:0023 SS:002b DS:002b ES:002b FS:0063 GS:006b EIP:6a2e848a ESP:0031f914 EBP:0031f918 EFLAGS:00010206( R- -- I - -P- ) EAX:00000000 EBX:8007274c ECX:00000000 EDX:0045d3e8 ESI:0031fa8c EDI:0031fd1c Stack dump: 0x0031f914: 8007274c 0031fbf8 0040f713 00000000 0x0031f924: 0045d3e8 8007274c 00f562b0 0031fa5c 0x0031f934: 00000002 00000000 00000000 00f565a0 0x0031f944: 00ef0000 00f54b50 00f562b0 0031f9a8 0x0031f954: 0031f9a0 0031f9a4 0040fa60 00000000 0x0031f964: 0040fd70 00000000 0031f9fc 0031fa3c Backtrace: =>0 0x6a2e848a _swprintf_p_l+0x3a(length=<is not available>, format=<is not available>, locale=<is not available>) [Z:\home\julliard\wine\wine\dlls\msvcrt\wcs.c:1845] in msvcrt (0x0031f918) 1 0x0040f713 test_WsCall+0x912(port=<is not available>) [Z:\home\julliard\wine\wine\dlls\webservices\tests\proxy.c:615] in webservices_test (0x0031fbf8) 2 0x0041164d func_proxy+0x125c() [Z:\home\julliard\wine\wine\dlls\webservices\tests\proxy.c:844] in webservices_test (0x0031fe08) 3 0x0045994b main+0x26a(argv=<is not available>) [Z:\home\julliard\wine\wine\include\wine\test.h:612] in webservices_test (0x0031fee8) 4 0x00458d3f mainCRTStartup+0x7e() [Z:\home\julliard\wine\wine\dlls\msvcrt\crt_main.c:58] in webservices_test (0x0031ff30) 5 0x7b62e250 WriteTapemark+0xff(type=<is not available>, count=<is not available>, immediate=<is not available>) [Z:\home\julliard\wine\wine\dlls\kernel32\tape.c:317] in kernel32 (0x0031ff48) 6 0x7bc555b7 RtlSleepConditionVariableSRW+0x226(lock=<is not available>, timeout=<is not available>, flags=<is not available>) [Z:\home\julliard\wine\wine\dlls\ntdll\sync.c:556] in ntdll (0x0031ff5c) 7 0x7bc55c70 call_thread_func+0xaf(arg=0x7ffd1000) [Z:\home\julliard\wine\wine\dlls\ntdll\thread.c:225] in ntdll (0x0031ffec) 0x6a2e848a _swprintf_p_l+0x3a [Z:\home\julliard\wine\wine\dlls\msvcrt\wcs.c:1845] in msvcrt: movzwl 0x0(%ecx),%eax 1845 while (*str1 && (*str1 == *str2))