server: Return WSA error codes in socket events.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2018-11-20 12:57:42 +01:00
parent f4b07ee8ec
commit f670a162a0
2 changed files with 80 additions and 64 deletions

View file

@ -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;
}

View file

@ -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)
{