From f670a162a0939be260cc4a84225fe8ba2c91f1f2 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 20 Nov 2018 12:57:42 +0100 Subject: [PATCH] server: Return WSA error codes in socket events. Signed-off-by: Alexandre Julliard --- dlls/ws2_32/socket.c | 113 +++++++++++++++++++++++++++---------------- server/sock.c | 31 ++++-------- 2 files changed, 80 insertions(+), 64 deletions(-) diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 2ac6b9fec59..2ea42694388 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -1038,41 +1038,74 @@ static UINT wsaHerrno(int loc_errno) } } -static inline DWORD NtStatusToWSAError( const DWORD status ) +static NTSTATUS sock_error_to_ntstatus( DWORD err ) +{ + switch (err) + { + case 0: return STATUS_SUCCESS; + case WSAEBADF: return STATUS_INVALID_HANDLE; + case WSAEACCES: return STATUS_ACCESS_DENIED; + case WSAEFAULT: return STATUS_NO_MEMORY; + case WSAEINVAL: return STATUS_INVALID_PARAMETER; + case WSAEMFILE: return STATUS_TOO_MANY_OPENED_FILES; + case WSAEWOULDBLOCK: return STATUS_CANT_WAIT; + case WSAEINPROGRESS: return STATUS_PENDING; + case WSAEALREADY: return STATUS_NETWORK_BUSY; + case WSAENOTSOCK: return STATUS_OBJECT_TYPE_MISMATCH; + case WSAEDESTADDRREQ: return STATUS_INVALID_PARAMETER; + case WSAEMSGSIZE: return STATUS_BUFFER_OVERFLOW; + case WSAEPROTONOSUPPORT: + case WSAESOCKTNOSUPPORT: + case WSAEPFNOSUPPORT: + case WSAEAFNOSUPPORT: + case WSAEPROTOTYPE: return STATUS_NOT_SUPPORTED; + case WSAENOPROTOOPT: return STATUS_INVALID_PARAMETER; + case WSAEOPNOTSUPP: return STATUS_NOT_SUPPORTED; + case WSAEADDRINUSE: return STATUS_ADDRESS_ALREADY_ASSOCIATED; + case WSAEADDRNOTAVAIL: return STATUS_INVALID_PARAMETER; + case WSAECONNREFUSED: return STATUS_CONNECTION_REFUSED; + case WSAESHUTDOWN: return STATUS_PIPE_DISCONNECTED; + case WSAENOTCONN: return STATUS_CONNECTION_DISCONNECTED; + case WSAETIMEDOUT: return STATUS_IO_TIMEOUT; + case WSAENETUNREACH: return STATUS_NETWORK_UNREACHABLE; + case WSAENETDOWN: return STATUS_NETWORK_BUSY; + case WSAECONNRESET: return STATUS_CONNECTION_RESET; + case WSAECONNABORTED: return STATUS_CONNECTION_ABORTED; + default: + FIXME("unmapped error %u\n", err); + return STATUS_UNSUCCESSFUL; + } +} + +static DWORD NtStatusToWSAError( DWORD status ) { - /* We only need to cover the status codes set by server async request handling */ - DWORD wserr; switch ( status ) { - case STATUS_SUCCESS: wserr = 0; break; - case STATUS_PENDING: wserr = WSA_IO_PENDING; break; - case STATUS_OBJECT_TYPE_MISMATCH: wserr = WSAENOTSOCK; break; - case STATUS_INVALID_HANDLE: wserr = WSAEBADF; break; - case STATUS_INVALID_PARAMETER: wserr = WSAEINVAL; break; - case STATUS_PIPE_DISCONNECTED: wserr = WSAESHUTDOWN; break; - case STATUS_NETWORK_BUSY: wserr = WSAEALREADY; break; - case STATUS_NETWORK_UNREACHABLE: wserr = WSAENETUNREACH; break; - case STATUS_CONNECTION_REFUSED: wserr = WSAECONNREFUSED; break; - case STATUS_CONNECTION_DISCONNECTED: wserr = WSAENOTCONN; break; - case STATUS_CONNECTION_RESET: wserr = WSAECONNRESET; break; - case STATUS_CONNECTION_ABORTED: wserr = WSAECONNABORTED; break; - case STATUS_CANCELLED: wserr = WSA_OPERATION_ABORTED; break; - case STATUS_ADDRESS_ALREADY_ASSOCIATED: wserr = WSAEADDRINUSE; break; + case STATUS_SUCCESS: return 0; + case STATUS_PENDING: return WSA_IO_PENDING; + case STATUS_OBJECT_TYPE_MISMATCH: return WSAENOTSOCK; + case STATUS_INVALID_HANDLE: return WSAEBADF; + case STATUS_INVALID_PARAMETER: return WSAEINVAL; + case STATUS_PIPE_DISCONNECTED: return WSAESHUTDOWN; + case STATUS_NETWORK_BUSY: return WSAEALREADY; + case STATUS_NETWORK_UNREACHABLE: return WSAENETUNREACH; + case STATUS_CONNECTION_REFUSED: return WSAECONNREFUSED; + case STATUS_CONNECTION_DISCONNECTED: return WSAENOTCONN; + case STATUS_CONNECTION_RESET: return WSAECONNRESET; + case STATUS_CONNECTION_ABORTED: return WSAECONNABORTED; + case STATUS_CANCELLED: return WSA_OPERATION_ABORTED; + case STATUS_ADDRESS_ALREADY_ASSOCIATED: return WSAEADDRINUSE; case STATUS_IO_TIMEOUT: - case STATUS_TIMEOUT: wserr = WSAETIMEDOUT; break; - case STATUS_NO_MEMORY: wserr = WSAEFAULT; break; - case STATUS_ACCESS_DENIED: wserr = WSAEACCES; break; - case STATUS_TOO_MANY_OPENED_FILES: wserr = WSAEMFILE; break; - case STATUS_CANT_WAIT: wserr = WSAEWOULDBLOCK; break; - case STATUS_BUFFER_OVERFLOW: wserr = WSAEMSGSIZE; break; - case STATUS_NOT_SUPPORTED: wserr = WSAEOPNOTSUPP; break; - case STATUS_HOST_UNREACHABLE: wserr = WSAEHOSTUNREACH; break; - - default: - wserr = RtlNtStatusToDosError( status ); - FIXME( "Status code %08x converted to DOS error code %x\n", status, wserr ); + case STATUS_TIMEOUT: return WSAETIMEDOUT; + case STATUS_NO_MEMORY: return WSAEFAULT; + case STATUS_ACCESS_DENIED: return WSAEACCES; + case STATUS_TOO_MANY_OPENED_FILES: return WSAEMFILE; + case STATUS_CANT_WAIT: return WSAEWOULDBLOCK; + case STATUS_BUFFER_OVERFLOW: return WSAEMSGSIZE; + case STATUS_NOT_SUPPORTED: return WSAEOPNOTSUPP; + case STATUS_HOST_UNREACHABLE: return WSAEHOSTUNREACH; + default: return RtlNtStatusToDosError( status ); } - return wserr; } /* set last error code from NT status without mapping WSA errors */ @@ -1164,7 +1197,7 @@ static void _get_sock_errors(SOCKET s, int *events) SERVER_END_REQ; } -static int _get_sock_error(SOCKET s, unsigned int bit) +static int get_sock_error(SOCKET s, unsigned int bit) { int events[FD_MAX_EVENTS]; _get_sock_errors(s, events); @@ -3460,13 +3493,8 @@ int WINAPI WS_connect(SOCKET s, const struct WS_sockaddr* name, int namelen) do_block(fd, POLLIN | POLLOUT, -1); _sync_sock_state(s); /* let wineserver notice connection */ /* retrieve any error codes from it */ - result = _get_sock_error(s, FD_CONNECT_BIT); - if (result) - SetLastError(NtStatusToWSAError(result)); - else - { - goto connect_success; - } + if (!(result = get_sock_error(s, FD_CONNECT_BIT))) goto connect_success; + SetLastError(result); } else { @@ -3589,7 +3617,7 @@ static BOOL WINAPI WS2_ConnectEx(SOCKET s, const struct WS_sockaddr* name, int n /* If the connect already failed */ if (status == STATUS_PIPE_DISCONNECTED) { - ov->Internal = _get_sock_error(s, FD_CONNECT_BIT); + ov->Internal = sock_error_to_ntstatus( get_sock_error( s, FD_CONNECT_BIT )); ov->InternalHigh = 0; if (cvalue) WS_AddCompletion( s, cvalue, ov->Internal, ov->InternalHigh, FALSE ); if (ov->hEvent) NtSetEvent( ov->hEvent, NULL ); @@ -3983,7 +4011,6 @@ INT WINAPI WS_getsockopt(SOCKET s, INT level, { if(events[i]) { - events[i] = NtStatusToWSAError(events[i]); TRACE("returning SO_ERROR %d from wine server\n", events[i]); *(int*) optval = events[i]; break; @@ -5079,10 +5106,10 @@ INT WINAPI WSAIoctl(SOCKET s, DWORD code, LPVOID in_buff, DWORD in_size, LPVOID else if (overlapped) { ULONG_PTR cvalue = (overlapped && ((ULONG_PTR)overlapped->hEvent & 1) == 0) ? (ULONG_PTR)overlapped : 0; - overlapped->Internal = status; + overlapped->Internal = sock_error_to_ntstatus( status ); overlapped->InternalHigh = total; + if (cvalue) WS_AddCompletion( HANDLE2SOCKET(s), cvalue, overlapped->Internal, total, FALSE ); if (overlapped->hEvent) NtSetEvent( overlapped->hEvent, NULL ); - if (cvalue) WS_AddCompletion( HANDLE2SOCKET(s), cvalue, status, total, FALSE ); } if (!status) @@ -7333,7 +7360,7 @@ int WINAPI WSAEnumNetworkEvents(SOCKET s, WSAEVENT hEvent, LPWSANETWORKEVENTS lp for (i = 0; i < FD_MAX_EVENTS; i++) { if (lpEvent->lNetworkEvents & (1 << i)) - lpEvent->iErrorCode[i] = NtStatusToWSAError(errors[i]); + lpEvent->iErrorCode[i] = errors[i]; } return 0; } diff --git a/server/sock.c b/server/sock.c index a8e6e28599b..3be24b396b2 100644 --- a/server/sock.c +++ b/server/sock.c @@ -109,7 +109,7 @@ struct sock user_handle_t window; /* window to send the message to */ unsigned int message; /* message to send */ obj_handle_t wparam; /* message wparam (socket handle) */ - int errors[FD_MAX_EVENTS]; /* event errors */ + unsigned int errors[FD_MAX_EVENTS]; /* event errors */ 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 */ @@ -134,7 +134,7 @@ static void sock_queue_async( struct fd *fd, struct async *async, int type, int static void sock_reselect_async( struct fd *fd, struct async_queue *queue ); static int sock_get_ntstatus( int err ); -static int sock_get_error( int err ); +static unsigned int sock_get_error( int err ); static void sock_set_error(void); static const struct object_ops sock_ops = @@ -292,7 +292,7 @@ static void sock_wake_up( struct sock *sock ) int event = event_bitorder[i]; if (sock->pmask & (1 << event)) { - lparam_t lparam = (1 << event) | (sock_get_error(sock->errors[event]) << 16); + lparam_t lparam = (1 << event) | (sock->errors[event] << 16); post_message( sock->window, sock->message, sock->wparam, lparam ); } } @@ -345,14 +345,14 @@ static void sock_dispatch_events( struct sock *sock, int prevstate, int event, i { sock->pmask |= FD_CONNECT; sock->hmask |= FD_CONNECT; - sock->errors[FD_CONNECT_BIT] = error; + sock->errors[FD_CONNECT_BIT] = sock_get_error( error ); goto end; } if (prevstate & FD_WINE_LISTENING) { sock->pmask |= FD_ACCEPT; sock->hmask |= FD_ACCEPT; - sock->errors[FD_ACCEPT_BIT] = error; + sock->errors[FD_ACCEPT_BIT] = sock_get_error( error ); goto end; } @@ -381,7 +381,7 @@ static void sock_dispatch_events( struct sock *sock, int prevstate, int event, i { sock->pmask |= FD_CLOSE; sock->hmask |= FD_CLOSE; - sock->errors[FD_CLOSE_BIT] = error; + sock->errors[FD_CLOSE_BIT] = sock_get_error( error ); } end: sock_wake_up( sock ); @@ -823,7 +823,7 @@ static int accept_into_socket( struct sock *sock, struct sock *acceptsock ) } /* return an errno value mapped to a WSA error */ -static int sock_get_error( int err ) +static unsigned int sock_get_error( int err ) { switch (err) { @@ -1265,24 +1265,13 @@ DECL_HANDLER(set_socket_event) DECL_HANDLER(get_socket_event) { struct sock *sock; - int i; - int errors[FD_MAX_EVENTS]; - sock = (struct sock *)get_handle_obj( current->process, req->handle, FILE_READ_ATTRIBUTES, &sock_ops ); - if (!sock) - { - reply->mask = 0; - reply->pmask = 0; - reply->state = 0; - return; - } + if (!(sock = (struct sock *)get_handle_obj( current->process, req->handle, + FILE_READ_ATTRIBUTES, &sock_ops ))) return; reply->mask = sock->mask; reply->pmask = sock->pmask; reply->state = sock->state; - for (i = 0; i < FD_MAX_EVENTS; i++) - errors[i] = sock_get_ntstatus(sock->errors[i]); - - set_reply_data( errors, min( get_reply_max_size(), sizeof(errors) )); + set_reply_data( sock->errors, min( get_reply_max_size(), sizeof(sock->errors) )); if (req->service) {