Signed-off-by: Zebediah Figura z.figura12@gmail.com --- include/wine/afd.h | 1 + server/sock.c | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+)
diff --git a/include/wine/afd.h b/include/wine/afd.h index d522b8a289f..ddf780500b7 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -175,6 +175,7 @@ struct afd_get_events_params #define IOCTL_AFD_WINE_GET_SO_RCVTIMEO CTL_CODE(FILE_DEVICE_NETWORK, 232, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_AFD_WINE_GET_SO_REUSEADDR CTL_CODE(FILE_DEVICE_NETWORK, 233, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_AFD_WINE_SET_SO_REUSEADDR CTL_CODE(FILE_DEVICE_NETWORK, 234, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_AFD_WINE_SET_SO_SNDBUF CTL_CODE(FILE_DEVICE_NETWORK, 235, METHOD_BUFFERED, FILE_ANY_ACCESS)
struct afd_create_params { diff --git a/server/sock.c b/server/sock.c index 94dbafe44ee..bcbf3d245be 100644 --- a/server/sock.c +++ b/server/sock.c @@ -2650,6 +2650,30 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) return 0; }
+ case IOCTL_AFD_WINE_SET_SO_SNDBUF: + { + DWORD sndbuf; + + if (get_req_data_size() < sizeof(sndbuf)) + { + set_error( STATUS_BUFFER_TOO_SMALL ); + return 0; + } + sndbuf = *(DWORD *)get_req_data(); + +#ifdef __APPLE__ + if (!sndbuf) + { + /* setsockopt fails if a zero value is passed */ + return 0; + } +#endif + + if (setsockopt( unix_fd, SOL_SOCKET, SO_SNDBUF, (char *)&sndbuf, sizeof(sndbuf) ) < 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 | 25 ++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/include/wine/afd.h b/include/wine/afd.h index ddf780500b7..f2a5abf726d 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -176,6 +176,7 @@ struct afd_get_events_params #define IOCTL_AFD_WINE_GET_SO_REUSEADDR CTL_CODE(FILE_DEVICE_NETWORK, 233, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_AFD_WINE_SET_SO_REUSEADDR CTL_CODE(FILE_DEVICE_NETWORK, 234, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_AFD_WINE_SET_SO_SNDBUF CTL_CODE(FILE_DEVICE_NETWORK, 235, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_AFD_WINE_GET_SO_SNDBUF CTL_CODE(FILE_DEVICE_NETWORK, 236, METHOD_BUFFERED, FILE_ANY_ACCESS)
struct afd_create_params { diff --git a/server/sock.c b/server/sock.c index bcbf3d245be..9a99e512c0d 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 sndbuf; /* advisory send 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? */ @@ -1389,6 +1390,7 @@ static struct sock *create_socket(void) sock->nonblocking = 0; sock->bound = 0; sock->rcvbuf = 0; + sock->sndbuf = 0; sock->rcvtimeo = 0; init_async_queue( &sock->read_q ); init_async_queue( &sock->write_q ); @@ -1552,6 +1554,10 @@ static int init_socket( struct sock *sock, int family, int type, int protocol, u if (!getsockopt( sockfd, SOL_SOCKET, SO_RCVBUF, &value, &len )) sock->rcvbuf = value;
+ len = sizeof(value); + if (!getsockopt( sockfd, SOL_SOCKET, SO_SNDBUF, &value, &len )) + sock->sndbuf = value; + sock->state = (type == WS_SOCK_STREAM ? SOCK_UNCONNECTED : SOCK_CONNECTIONLESS); sock->flags = flags; sock->proto = protocol; @@ -2650,6 +2656,20 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) return 0; }
+ case IOCTL_AFD_WINE_GET_SO_SNDBUF: + { + int sndbuf = sock->sndbuf; + + if (get_reply_max_size() < sizeof(sndbuf)) + { + set_error( STATUS_BUFFER_TOO_SMALL ); + return 0; + } + + set_reply_data( &sndbuf, sizeof(sndbuf) ); + return 1; + } + case IOCTL_AFD_WINE_SET_SO_SNDBUF: { DWORD sndbuf; @@ -2665,11 +2685,14 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) if (!sndbuf) { /* setsockopt fails if a zero value is passed */ + sock->sndbuf = sndbuf; return 0; } #endif
- if (setsockopt( unix_fd, SOL_SOCKET, SO_SNDBUF, (char *)&sndbuf, sizeof(sndbuf) ) < 0) + if (!setsockopt( unix_fd, SOL_SOCKET, SO_SNDBUF, (char *)&sndbuf, sizeof(sndbuf) )) + sock->sndbuf = sndbuf; + else set_error( sock_get_ntstatus( errno ) ); return 0; }
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/socket.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 89fb7d3462b..3f15bb4e39b 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -3575,21 +3575,8 @@ int WINAPI WS_setsockopt(SOCKET s, int level, int optname, case WS_SO_REUSEADDR: return server_setsockopt( s, IOCTL_AFD_WINE_SET_SO_REUSEADDR, 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 - * setsockopt follow below that.*/ - case WS_SO_SNDBUF: - if (!*(const int *)optval) - { - FIXME("SO_SNDBUF ignoring request to disable send buffering\n"); -#ifdef __APPLE__ - return 0; -#endif - } - convert_sockopt(&level, &optname); - break; + return server_setsockopt( s, IOCTL_AFD_WINE_SET_SO_SNDBUF, optval, optlen );
/* SO_DEBUG is a privileged operation, ignore it. */ case WS_SO_DEBUG:
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=8606 Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/socket.c | 17 +++-------------- dlls/ws2_32/tests/sock.c | 2 +- 2 files changed, 4 insertions(+), 15 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 3f15bb4e39b..562d05ed4be 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -2088,20 +2088,6 @@ INT WINAPI WS_getsockopt(SOCKET s, INT level, case WS_SO_BROADCAST: return server_getsockopt( s, IOCTL_AFD_WINE_GET_SO_BROADCAST, optval, optlen );
- /* Handle common cases. The special cases are below, sorted - * alphabetically */ - case WS_SO_SNDBUF: - if ( (fd = get_sock_fd( s, 0, NULL )) == -1) - return SOCKET_ERROR; - convert_sockopt(&level, &optname); - if (getsockopt(fd, level, optname, optval, (socklen_t *)optlen) != 0 ) - { - SetLastError(wsaErrno()); - ret = SOCKET_ERROR; - } - release_sock_fd( s, fd ); - return ret; - case WS_SO_BSP_STATE: { CSADDR_INFO *csinfo = (CSADDR_INFO *)optval; @@ -2293,6 +2279,9 @@ INT WINAPI WS_getsockopt(SOCKET s, INT level, case WS_SO_REUSEADDR: return server_getsockopt( s, IOCTL_AFD_WINE_GET_SO_REUSEADDR, optval, optlen );
+ case WS_SO_SNDBUF: + return server_getsockopt( s, IOCTL_AFD_WINE_GET_SO_SNDBUF, optval, optlen ); + case WS_SO_SNDTIMEO: { INT64 timeout; diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index a3f7e002ce7..e579b72ecb5 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -1214,7 +1214,7 @@ static void test_set_getsockopt(void) value = 0xdeadbeef; err = getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&value, &size); ok( !err, "getsockopt(SO_SNDBUF) 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_RCVBUF */ value = 4096;
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/socket.c | 70 +++----------------------------------------- include/wine/afd.h | 2 ++ server/sock.c | 40 ++++++++++++++++++++----- 3 files changed, 39 insertions(+), 73 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 562d05ed4be..ce71e25d63d 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -913,34 +913,6 @@ static int convert_sockopt(INT *level, INT *optname) return 0; }
-/* Utility: get the SO_RCVTIMEO or SO_SNDTIMEO socket option - * from an fd and return the value converted to milli seconds - * or 0 if there is an infinite time out */ -static inline INT64 get_rcvsnd_timeo( int fd, BOOL is_recv) -{ - struct timeval tv; - socklen_t len = sizeof(tv); - int optname, res; - - if (is_recv) -#ifdef SO_RCVTIMEO - optname = SO_RCVTIMEO; -#else - return 0; -#endif - else -#ifdef SO_SNDTIMEO - optname = SO_SNDTIMEO; -#else - return 0; -#endif - - res = getsockopt(fd, SOL_SOCKET, optname, &tv, &len); - if (res < 0) - return 0; - return (UINT64)tv.tv_sec * 1000 + tv.tv_usec / 1000; -} - int convert_socktype_w2u(int windowssocktype) { unsigned int i; @@ -2283,23 +2255,8 @@ INT WINAPI WS_getsockopt(SOCKET s, INT level, return server_getsockopt( s, IOCTL_AFD_WINE_GET_SO_SNDBUF, optval, optlen );
case WS_SO_SNDTIMEO: - { - INT64 timeout; + return server_getsockopt( s, IOCTL_AFD_WINE_GET_SO_SNDTIMEO, optval, optlen );
- if (!optlen || *optlen < sizeof(int)|| !optval) - { - SetLastError(WSAEFAULT); - return SOCKET_ERROR; - } - if ( (fd = get_sock_fd( s, 0, NULL )) == -1) - return SOCKET_ERROR; - - timeout = get_rcvsnd_timeo(fd, optname == WS_SO_RCVTIMEO); - *(int *)optval = timeout <= UINT_MAX ? timeout : UINT_MAX; - - release_sock_fd( s, fd ); - return ret; - } case WS_SO_TYPE: { int sock_type; @@ -3504,7 +3461,6 @@ int WINAPI WS_setsockopt(SOCKET s, int level, int optname, { int fd; int woptval; - struct timeval tval; struct ip_mreq_source mreq_source;
TRACE("(socket %04lx, %s, optval %s, optlen %d)\n", s, @@ -3567,6 +3523,9 @@ int WINAPI WS_setsockopt(SOCKET s, int level, int optname, case WS_SO_SNDBUF: return server_setsockopt( s, IOCTL_AFD_WINE_SET_SO_SNDBUF, optval, optlen );
+ case WS_SO_SNDTIMEO: + return server_setsockopt( s, IOCTL_AFD_WINE_SET_SO_SNDTIMEO, optval, optlen ); + /* SO_DEBUG is a privileged operation, ignore it. */ case WS_SO_DEBUG: TRACE("Ignoring SO_DEBUG\n"); @@ -3607,27 +3566,6 @@ 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_SNDTIMEO - case WS_SO_SNDTIMEO: - if (optval && optlen == sizeof(UINT32)) { - /* WinSock passes milliseconds instead of struct timeval */ - tval.tv_usec = (*(const UINT32*)optval % 1000) * 1000; - tval.tv_sec = *(const UINT32*)optval / 1000; - /* min of 500 milliseconds */ - if (tval.tv_sec == 0 && tval.tv_usec && tval.tv_usec < 500000) - tval.tv_usec = 500000; - optlen = sizeof(struct timeval); - optval = (char*)&tval; - } else if (optlen == sizeof(struct timeval)) { - WARN("SO_SND/RCVTIMEO for %d bytes: assuming unixism\n", optlen); - } else { - WARN("SO_SND/RCVTIMEO for %d bytes is weird: ignored\n", optlen); - return 0; - } - convert_sockopt(&level, &optname); - break; -#endif - case WS_SO_RANDOMIZE_PORT: FIXME("Ignoring WS_SO_RANDOMIZE_PORT\n"); return 0; diff --git a/include/wine/afd.h b/include/wine/afd.h index f2a5abf726d..44a8b1a5ff9 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -177,6 +177,8 @@ struct afd_get_events_params #define IOCTL_AFD_WINE_SET_SO_REUSEADDR CTL_CODE(FILE_DEVICE_NETWORK, 234, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_AFD_WINE_SET_SO_SNDBUF CTL_CODE(FILE_DEVICE_NETWORK, 235, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_AFD_WINE_GET_SO_SNDBUF CTL_CODE(FILE_DEVICE_NETWORK, 236, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_AFD_WINE_GET_SO_SNDTIMEO CTL_CODE(FILE_DEVICE_NETWORK, 237, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_AFD_WINE_SET_SO_SNDTIMEO CTL_CODE(FILE_DEVICE_NETWORK, 238, METHOD_BUFFERED, FILE_ANY_ACCESS)
struct afd_create_params { diff --git a/server/sock.c b/server/sock.c index 9a99e512c0d..befa9117c13 100644 --- a/server/sock.c +++ b/server/sock.c @@ -210,6 +210,7 @@ struct sock unsigned int rcvbuf; /* advisory recv buffer size */ unsigned int sndbuf; /* advisory send buffer size */ unsigned int rcvtimeo; /* receive timeout in ms */ + unsigned int sndtimeo; /* send 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? */ @@ -1392,6 +1393,7 @@ static struct sock *create_socket(void) sock->rcvbuf = 0; sock->sndbuf = 0; sock->rcvtimeo = 0; + sock->sndtimeo = 0; init_async_queue( &sock->read_q ); init_async_queue( &sock->write_q ); init_async_queue( &sock->ifchange_q ); @@ -2697,6 +2699,35 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) return 0; }
+ case IOCTL_AFD_WINE_GET_SO_SNDTIMEO: + { + DWORD sndtimeo = sock->sndtimeo; + + if (get_reply_max_size() < sizeof(sndtimeo)) + { + set_error( STATUS_BUFFER_TOO_SMALL ); + return 0; + } + + set_reply_data( &sndtimeo, sizeof(sndtimeo) ); + return 1; + } + + case IOCTL_AFD_WINE_SET_SO_SNDTIMEO: + { + DWORD sndtimeo; + + if (get_req_data_size() < sizeof(sndtimeo)) + { + set_error( STATUS_BUFFER_TOO_SMALL ); + return 0; + } + sndtimeo = *(DWORD *)get_req_data(); + + sock->sndtimeo = sndtimeo; + return 0; + } + default: set_error( STATUS_NOT_SUPPORTED ); return 0; @@ -3217,19 +3248,14 @@ DECL_HANDLER(send_socket) /* send() returned EWOULDBLOCK or a short write, i.e. cannot send all data yet */ if (status == STATUS_DEVICE_NOT_READY && !sock->nonblocking) { -#ifdef SO_SNDTIMEO - 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 WSASend*() 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_SNDTIMEO, (char *)&tv, &len )) - timeout = tv.tv_sec * -10000000 + tv.tv_usec * -10; -#endif + if (is_fd_overlapped( fd )) + timeout = (timeout_t)sock->sndtimeo * -10000;
status = STATUS_PENDING; }