Signed-off-by: Alex Henrie alexhenrie24@gmail.com --- This patch was previously assigned to Zeb Figura, but dropped off the patches list without review. --- dlls/ws2_32/socket.c | 4 +--- dlls/ws2_32/tests/sock.c | 10 ++++++++-- include/wine/afd.h | 1 + server/sock.c | 38 +++++++++++++++++++++++++++----------- 4 files changed, 37 insertions(+), 16 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 2db441bee3c..2c2eabc09fa 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -2750,9 +2750,7 @@ int WINAPI setsockopt( SOCKET s, int level, int optname, const char *optval, int }
case SO_ERROR: - FIXME( "SO_ERROR, stub!\n" ); - SetLastError( WSAENOPROTOOPT ); - return -1; + return server_setsockopt( s, IOCTL_AFD_WINE_SET_SO_ERROR, optval, optlen );
case SO_KEEPALIVE: return server_setsockopt( s, IOCTL_AFD_WINE_SET_SO_KEEPALIVE, optval, optlen ); diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 02713a7c625..76f4f1ef8a2 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -1289,7 +1289,6 @@ static void test_set_getsockopt(void) SetLastError(0xdeadbeef); i = 1234; err = setsockopt(s, SOL_SOCKET, SO_ERROR, (char *) &i, size); -todo_wine ok( !err && !WSAGetLastError(), "got %d with %d (expected 0 with 0)\n", err, WSAGetLastError()); @@ -1300,7 +1299,14 @@ todo_wine ok( !err && !WSAGetLastError(), "got %d with %d (expected 0 with 0)\n", err, WSAGetLastError()); -todo_wine + ok (i == 1234, "got %d (expected 1234)\n", i); + + SetLastError(0xdeadbeef); + i = 4321; + err = getsockopt(s, SOL_SOCKET, SO_ERROR, (char *) &i, &size); + ok( !err && !WSAGetLastError(), + "got %d with %d (expected 0 with 0)\n", + err, WSAGetLastError()); ok (i == 1234, "got %d (expected 1234)\n", i);
/* Test invalid optlen */ diff --git a/include/wine/afd.h b/include/wine/afd.h index 3b8bdcb9e5d..9382e2acf2f 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -238,6 +238,7 @@ struct afd_get_events_params #define IOCTL_AFD_WINE_SET_IP_RECVTTL WINE_AFD_IOC(294) #define IOCTL_AFD_WINE_GET_IP_RECVTOS WINE_AFD_IOC(295) #define IOCTL_AFD_WINE_SET_IP_RECVTOS WINE_AFD_IOC(296) +#define IOCTL_AFD_WINE_SET_SO_ERROR WINE_AFD_IOC(297)
struct afd_create_params { diff --git a/server/sock.c b/server/sock.c index c9b71137c4c..cfb65e0b54c 100644 --- a/server/sock.c +++ b/server/sock.c @@ -191,6 +191,7 @@ struct sock unsigned int message; /* message to send */ obj_handle_t wparam; /* message wparam (socket handle) */ int errors[AFD_POLL_BIT_COUNT]; /* event errors */ + unsigned int last_error; /* most recent error code */ timeout_t connect_time;/* time the socket was connected */ struct sock *deferred; /* socket that waits for a deferred accept */ struct async_queue read_q; /* queue for asynchronous reads */ @@ -963,6 +964,7 @@ static void post_socket_event( struct sock *sock, enum afd_poll_bit event_bit, i sock->pending_events |= event; sock->reported_events |= event; sock->errors[event_bit] = error; + sock->last_error = sock_get_error( error ); } }
@@ -978,6 +980,7 @@ static void sock_dispatch_events( struct sock *sock, enum connection_state prevs { post_socket_event( sock, AFD_POLL_BIT_CONNECT, 0 ); sock->errors[AFD_POLL_BIT_CONNECT_ERR] = 0; + sock->last_error = 0; } if (event & (POLLERR | POLLHUP)) post_socket_event( sock, AFD_POLL_BIT_CONNECT_ERR, error ); @@ -1441,6 +1444,7 @@ static struct sock *create_socket(void) init_async_queue( &sock->connect_q ); init_async_queue( &sock->poll_q ); memset( sock->errors, 0, sizeof(sock->errors) ); + sock->last_error = 0; list_init( &sock->accept_list ); return sock; } @@ -2675,7 +2679,6 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) { int error; socklen_t len = sizeof(error); - unsigned int i;
if (get_reply_max_size() < sizeof(error)) { @@ -2689,19 +2692,32 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) return; }
- if (!error) + if (error) + sock->last_error = sock_get_error( error ); + + set_reply_data( &sock->last_error, sizeof(sock->last_error) ); + return; + } + + case IOCTL_AFD_WINE_SET_SO_ERROR: + { + int error; + socklen_t len = sizeof(error); + + if (get_req_data_size() < sizeof(sock->last_error)) { - for (i = 0; i < ARRAY_SIZE( sock->errors ); ++i) - { - if (sock->errors[i]) - { - error = sock_get_error( sock->errors[i] ); - break; - } - } + set_error( STATUS_BUFFER_TOO_SMALL ); + return; + } + + /* clear the native error, if any */ + if (getsockopt( unix_fd, SOL_SOCKET, SO_ERROR, (char *)&error, &len ) < 0) + { + set_error( sock_get_ntstatus( errno ) ); + return; }
- set_reply_data( &error, sizeof(error) ); + sock->last_error = *(unsigned int *)get_req_data(); return; }