From 798c9e5161955c75231343eff0e92536cacb8360 Mon Sep 17 00:00:00 2001 From: Mike Kaplinskiy Date: Mon, 22 Mar 2010 14:56:21 -0400 Subject: [PATCH] ws2_32: Use ntstatus in overlapped functions. --- dlls/ws2_32/socket.c | 148 ++++++++++++++++++++++++++++++++----------- server/sock.c | 69 +++++++++++++++++--- 2 files changed, 170 insertions(+), 47 deletions(-) diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 1af90b1db02..ac9fe756c0c 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -424,12 +424,53 @@ static const char magic_loopback_addr[] = {127, 12, 34, 56}; /* ----------------------------------- error handling */ -static UINT wsaErrno(void) +static NTSTATUS sock_get_ntstatus( int err ) { - int loc_errno = errno; - WARN("errno %d, (%s).\n", loc_errno, strerror(loc_errno)); + switch ( err ) + { + case EBADF: return STATUS_INVALID_HANDLE; + case EBUSY: return STATUS_DEVICE_BUSY; + case EPERM: + case EACCES: return STATUS_ACCESS_DENIED; + case EFAULT: return STATUS_NO_MEMORY; + case EINVAL: return STATUS_INVALID_PARAMETER; + case ENFILE: + case EMFILE: return STATUS_TOO_MANY_OPENED_FILES; + case EWOULDBLOCK: return STATUS_CANT_WAIT; + case EINPROGRESS: return STATUS_PENDING; + case EALREADY: return STATUS_NETWORK_BUSY; + case ENOTSOCK: return STATUS_OBJECT_TYPE_MISMATCH; + case EDESTADDRREQ: return STATUS_INVALID_PARAMETER; + case EMSGSIZE: return STATUS_BUFFER_OVERFLOW; + case EPROTONOSUPPORT: + case ESOCKTNOSUPPORT: + case EPFNOSUPPORT: + case EAFNOSUPPORT: + case EPROTOTYPE: return STATUS_NOT_SUPPORTED; + case ENOPROTOOPT: return STATUS_INVALID_PARAMETER; + case EOPNOTSUPP: return STATUS_NOT_SUPPORTED; + case EADDRINUSE: return STATUS_ADDRESS_ALREADY_ASSOCIATED; + case EADDRNOTAVAIL: return STATUS_INVALID_PARAMETER; + case ECONNREFUSED: return STATUS_CONNECTION_REFUSED; + case ESHUTDOWN: return STATUS_PIPE_DISCONNECTED; + case ENOTCONN: return STATUS_CONNECTION_DISCONNECTED; + case ETIMEDOUT: return STATUS_IO_TIMEOUT; + case ENETUNREACH: return STATUS_NETWORK_UNREACHABLE; + case ENETDOWN: return STATUS_NETWORK_BUSY; + case EPIPE: + case ECONNRESET: return STATUS_CONNECTION_RESET; + case ECONNABORTED: return STATUS_CONNECTION_ABORTED; - switch(loc_errno) + case 0: return STATUS_SUCCESS; + default: + WARN("Unknown errno %d!\n", err); + return STATUS_UNSUCCESSFUL; + } +} + +static UINT sock_get_error( int err ) +{ + switch(err) { case EINTR: return WSAEINTR; case EBADF: return WSAEBADF; @@ -487,17 +528,33 @@ static UINT wsaErrno(void) case EREMOTE: return WSAEREMOTE; #endif - /* just in case we ever get here and there are no problems */ + /* just in case we ever get here and there are no problems */ case 0: return 0; - default: - WARN("Unknown errno %d!\n", loc_errno); + default: + WARN("Unknown errno %d!\n", err); return WSAEOPNOTSUPP; } } +static UINT wsaErrno(void) +{ + int loc_errno = errno; + WARN("errno %d, (%s).\n", loc_errno, strerror(loc_errno)); + + return sock_get_error( loc_errno ); +} + +/* most ws2 overlapped functions return an ntstatus-based error code */ +static NTSTATUS wsaErrStatus(void) +{ + int loc_errno = errno; + WARN("errno %d, (%s).\n", loc_errno, strerror(loc_errno)); + + return sock_get_ntstatus(loc_errno); +} + static UINT wsaHerrno(int loc_errno) { - WARN("h_errno %d.\n", loc_errno); switch(loc_errno) @@ -509,7 +566,7 @@ static UINT wsaHerrno(int loc_errno) case ENOBUFS: return WSAENOBUFS; case 0: return 0; - default: + default: WARN("Unknown h_errno %d!\n", loc_errno); return WSAEOPNOTSUPP; } @@ -521,24 +578,32 @@ static inline DWORD NtStatusToWSAError( const DWORD status ) 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_CANCELLED: wserr = WSA_OPERATION_ABORTED; break; - case STATUS_TIMEOUT: wserr = WSAETIMEDOUT; break; - case STATUS_NO_MEMORY: wserr = WSAEFAULT; break; + 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_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; + default: - if ( status >= WSABASEERR && status <= WSABASEERR+1004 ) - /* It is not an NT status code but a winsock error */ - wserr = status; - else - { - wserr = RtlNtStatusToDosError( status ); - FIXME( "Status code %08x converted to DOS error code %x\n", status, wserr ); - } + wserr = RtlNtStatusToDosError( status ); + FIXME( "Status code %08x converted to DOS error code %x\n", status, wserr ); } return wserr; } @@ -1365,7 +1430,7 @@ static NTSTATUS WS2_async_recv( void* user, IO_STATUS_BLOCK* iosb, NTSTATUS stat else { result = 0; - status = wsaErrno(); /* FIXME: is this correct ???? */ + status = wsaErrStatus(); } } break; @@ -1473,9 +1538,7 @@ static NTSTATUS WS2_async_send(void* user, IO_STATUS_BLOCK* iosb, NTSTATUS statu } else { - /* We set the status to a winsock error code and check for that - later in NtStatusToWSAError () */ - status = wsaErrno(); + status = wsaErrStatus(); result = 0; } } @@ -1511,8 +1574,8 @@ static NTSTATUS WS2_async_shutdown( void* user, PIO_STATUS_BLOCK iosb, NTSTATUS case ASYNC_TYPE_READ: err = shutdown( fd, 0 ); break; case ASYNC_TYPE_WRITE: err = shutdown( fd, 1 ); break; } + status = err ? wsaErrStatus() : STATUS_SUCCESS; wine_server_release_fd( wsa->hSocket, fd ); - status = err ? wsaErrno() : STATUS_SUCCESS; break; } iosb->u.Status = status; @@ -1590,7 +1653,7 @@ SOCKET WINAPI WS_accept(SOCKET s, struct WS_sockaddr *addr, if (addr) WS_getpeername(as, addr, addrlen32); return as; } - if (is_blocking && status == WSAEWOULDBLOCK) + if (is_blocking && status == STATUS_CANT_WAIT) { int fd = get_sock_fd( s, FILE_READ_DATA, NULL ); /* block here */ @@ -1598,7 +1661,7 @@ SOCKET WINAPI WS_accept(SOCKET s, struct WS_sockaddr *addr, _sync_sock_state(s); /* let wineserver notice connection */ release_sock_fd( s, fd ); } - } while (is_blocking && status == WSAEWOULDBLOCK); + } while (is_blocking && status == STATUS_CANT_WAIT); set_error(status); return INVALID_SOCKET; @@ -1747,7 +1810,7 @@ int WINAPI WS_connect(SOCKET s, const struct WS_sockaddr* name, int namelen) /* retrieve any error codes from it */ result = _get_sock_error(s, FD_CONNECT_BIT); if (result) - SetLastError(result); + SetLastError(NtStatusToWSAError(result)); else { goto connect_success; @@ -3044,8 +3107,9 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, } if (n == -1 && errno != EAGAIN) { + int loc_errno = errno; err = wsaErrno(); - if (cvalue) WS_AddCompletion( s, cvalue, err, 0 ); + if (cvalue) WS_AddCompletion( s, cvalue, sock_get_ntstatus(loc_errno), 0 ); goto error; } @@ -4227,6 +4291,8 @@ int WINAPI WS_gethostname(char *name, int namelen) int WINAPI WSAEnumNetworkEvents(SOCKET s, WSAEVENT hEvent, LPWSANETWORKEVENTS lpEvent) { int ret; + int i; + int errors[FD_MAX_EVENTS]; TRACE("%08lx, hEvent %p, lpEvent %p\n", s, hEvent, lpEvent ); @@ -4235,11 +4301,16 @@ int WINAPI WSAEnumNetworkEvents(SOCKET s, WSAEVENT hEvent, LPWSANETWORKEVENTS lp req->handle = wine_server_obj_handle( SOCKET2HANDLE(s) ); req->service = TRUE; req->c_event = wine_server_obj_handle( hEvent ); - wine_server_set_reply( req, lpEvent->iErrorCode, sizeof(lpEvent->iErrorCode) ); + wine_server_set_reply( req, errors, sizeof(errors) ); if (!(ret = wine_server_call(req))) lpEvent->lNetworkEvents = reply->pmask & reply->mask; } SERVER_END_REQ; - if (!ret) return 0; + if (!ret) + { + for (i = 0; i < FD_MAX_EVENTS; i++) + lpEvent->iErrorCode[i] = NtStatusToWSAError(errors[i]); + return 0; + } SetLastError(WSAEINVAL); return SOCKET_ERROR; } @@ -4794,8 +4865,9 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, if (errno == EINTR) continue; if (errno != EAGAIN) { + int loc_errno = errno; err = wsaErrno(); - if (cvalue) WS_AddCompletion( s, cvalue, err, 0 ); + if (cvalue) WS_AddCompletion( s, cvalue, sock_get_ntstatus(loc_errno), 0 ); goto error; } } diff --git a/server/sock.c b/server/sock.c index 5eaed6b79da..b460fa74071 100644 --- a/server/sock.c +++ b/server/sock.c @@ -123,6 +123,7 @@ static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, static void sock_reselect_async( struct fd *fd, struct async_queue *queue ); static void sock_cancel_async( struct fd *fd, struct process *process, struct thread *thread, client_ptr_t iosb ); +static int sock_get_ntstatus( int err ); static int sock_get_error( int err ); static void sock_set_error(void); @@ -302,7 +303,7 @@ static void sock_wake_up( struct sock *sock, int pollev ) int event = event_bitorder[i]; if (sock->pmask & (1 << event)) { - lparam_t lparam = (1 << event) | (sock->errors[event] << 16); + lparam_t lparam = (1 << event) | (sock_get_error(sock->errors[event]) << 16); post_message( sock->window, sock->message, sock->wparam, lparam ); } } @@ -317,7 +318,7 @@ static inline int sock_error( struct fd *fd ) optlen = sizeof(optval); getsockopt( get_unix_fd(fd), SOL_SOCKET, SO_ERROR, (void *) &optval, &optlen); - return optval ? sock_get_error(optval) : 0; + return optval; } static void sock_poll_event( struct fd *fd, int event ) @@ -636,6 +637,7 @@ static struct object *create_socket( int family, int type, int protocol, unsigne sock->deferred = NULL; sock->read_q = NULL; sock->write_q = NULL; + memset( sock->errors, 0, sizeof(sock->errors) ); if (!(sock->fd = create_anonymous_fd( &sock_fd_ops, sockfd, &sock->obj, (flags & WSA_FLAG_OVERLAPPED) ? 0 : FILE_SYNCHRONOUS_IO_NONALERT ))) { @@ -706,6 +708,7 @@ static struct sock *accept_socket( obj_handle_t handle ) acceptsock->deferred = NULL; acceptsock->read_q = NULL; acceptsock->write_q = NULL; + memset( acceptsock->errors, 0, sizeof(acceptsock->errors) ); if (!(acceptsock->fd = create_anonymous_fd( &sock_fd_ops, acceptfd, &acceptsock->obj, get_fd_options( sock->fd ) ))) { @@ -782,6 +785,8 @@ static int sock_get_error( int err ) #ifdef EREMOTE case EREMOTE: return WSAEREMOTE; #endif + + case 0: return 0; default: errno = err; perror("wineserver: sock_get_error() can't map error"); @@ -789,10 +794,55 @@ static int sock_get_error( int err ) } } +static int sock_get_ntstatus( int err ) +{ + switch ( err ) + { + case EBADF: return STATUS_INVALID_HANDLE; + case EBUSY: return STATUS_DEVICE_BUSY; + case EPERM: + case EACCES: return STATUS_ACCESS_DENIED; + case EFAULT: return STATUS_NO_MEMORY; + case EINVAL: return STATUS_INVALID_PARAMETER; + case ENFILE: + case EMFILE: return STATUS_TOO_MANY_OPENED_FILES; + case EWOULDBLOCK: return STATUS_CANT_WAIT; + case EINPROGRESS: return STATUS_PENDING; + case EALREADY: return STATUS_NETWORK_BUSY; + case ENOTSOCK: return STATUS_OBJECT_TYPE_MISMATCH; + case EDESTADDRREQ: return STATUS_INVALID_PARAMETER; + case EMSGSIZE: return STATUS_BUFFER_OVERFLOW; + case EPROTONOSUPPORT: + case ESOCKTNOSUPPORT: + case EPFNOSUPPORT: + case EAFNOSUPPORT: + case EPROTOTYPE: return STATUS_NOT_SUPPORTED; + case ENOPROTOOPT: return STATUS_INVALID_PARAMETER; + case EOPNOTSUPP: return STATUS_NOT_SUPPORTED; + case EADDRINUSE: return STATUS_ADDRESS_ALREADY_ASSOCIATED; + case EADDRNOTAVAIL: return STATUS_INVALID_PARAMETER; + case ECONNREFUSED: return STATUS_CONNECTION_REFUSED; + case ESHUTDOWN: return STATUS_PIPE_DISCONNECTED; + case ENOTCONN: return STATUS_CONNECTION_DISCONNECTED; + case ETIMEDOUT: return STATUS_IO_TIMEOUT; + case ENETUNREACH: return STATUS_NETWORK_UNREACHABLE; + case ENETDOWN: return STATUS_NETWORK_BUSY; + case EPIPE: + case ECONNRESET: return STATUS_CONNECTION_RESET; + case ECONNABORTED: return STATUS_CONNECTION_ABORTED; + + case 0: return STATUS_SUCCESS; + default: + errno = err; + perror("wineserver: sock_get_ntstatus() can't map error"); + return STATUS_UNSUCCESSFUL; + } +} + /* set the last error depending on errno */ static void sock_set_error(void) { - set_error( sock_get_error( errno ) ); + set_error( sock_get_ntstatus( errno ) ); } /* create a socket */ @@ -863,6 +913,8 @@ 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) @@ -870,13 +922,15 @@ DECL_HANDLER(get_socket_event) reply->mask = 0; reply->pmask = 0; reply->state = 0; - set_error( WSAENOTSOCK ); return; } reply->mask = sock->mask; reply->pmask = sock->pmask; reply->state = sock->state; - set_reply_data( sock->errors, min( get_reply_max_size(), sizeof(sock->errors) )); + 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) )); if (req->service) { @@ -926,15 +980,12 @@ DECL_HANDLER(set_socket_deferred) sock=(struct sock *)get_handle_obj( current->process, req->handle, FILE_WRITE_ATTRIBUTES, &sock_ops ); if ( !sock ) - { - set_error( WSAENOTSOCK ); return; - } + acceptsock = (struct sock *)get_handle_obj( current->process, req->deferred, 0, &sock_ops ); if ( !acceptsock ) { release_object( sock ); - set_error( WSAENOTSOCK ); return; } sock->deferred = acceptsock;