Commit 93fb921c authored by Zebediah Figura's avatar Zebediah Figura Committed by Alexandre Julliard

ws2_32: Use server-side async I/O in accept().

parent 0bbd3f66
...@@ -2673,55 +2673,50 @@ static int WS2_register_async_shutdown( SOCKET s, int type ) ...@@ -2673,55 +2673,50 @@ static int WS2_register_async_shutdown( SOCKET s, int type )
/*********************************************************************** /***********************************************************************
* accept (WS2_32.1) * accept (WS2_32.1)
*/ */
SOCKET WINAPI WS_accept(SOCKET s, struct WS_sockaddr *addr, int *addrlen32) SOCKET WINAPI WS_accept( SOCKET s, struct WS_sockaddr *addr, int *len )
{ {
DWORD err;
int fd;
BOOL is_blocking;
IO_STATUS_BLOCK io; IO_STATUS_BLOCK io;
NTSTATUS status; NTSTATUS status;
obj_handle_t accept_handle; obj_handle_t accept_handle;
HANDLE sync_event;
SOCKET ret;
TRACE("socket %04lx\n", s ); TRACE("%#lx\n", s);
err = sock_is_blocking(s, &is_blocking);
if (err)
goto error;
for (;;) if (!(sync_event = CreateEventW( NULL, TRUE, FALSE, NULL ))) return INVALID_SOCKET;
status = NtDeviceIoControlFile( SOCKET2HANDLE(s), (HANDLE)((ULONG_PTR)sync_event | 0), NULL, NULL, &io,
IOCTL_AFD_ACCEPT, NULL, 0, &accept_handle, sizeof(accept_handle) );
if (status == STATUS_PENDING)
{ {
status = NtDeviceIoControlFile( SOCKET2HANDLE(s), NULL, NULL, NULL, &io, IOCTL_AFD_ACCEPT, if (WaitForSingleObject( sync_event, INFINITE ) == WAIT_FAILED)
NULL, 0, &accept_handle, sizeof(accept_handle) );
if (!status)
{ {
SOCKET as = HANDLE2SOCKET(wine_server_ptr_handle( accept_handle )); CloseHandle( sync_event );
return SOCKET_ERROR;
}
status = io.u.Status;
}
CloseHandle( sync_event );
if (status)
{
WARN("failed; status %#x\n", status);
WSASetLastError( NtStatusToWSAError( status ) );
return INVALID_SOCKET;
}
if (!socket_list_add(as)) ret = HANDLE2SOCKET(wine_server_ptr_handle( accept_handle ));
{ if (!socket_list_add( ret ))
CloseHandle(SOCKET2HANDLE(as)); {
return SOCKET_ERROR; CloseHandle( SOCKET2HANDLE(ret) );
} return INVALID_SOCKET;
if (addr && addrlen32 && WS_getpeername(as, addr, addrlen32)) }
{ if (addr && len && WS_getpeername( ret, addr, len ))
WS_closesocket(as); {
return SOCKET_ERROR; WS_closesocket( ret );
} return INVALID_SOCKET;
TRACE("\taccepted %04lx\n", as);
return as;
}
err = NtStatusToWSAError( status );
if (!is_blocking) break;
if (err != WSAEWOULDBLOCK) break;
fd = get_sock_fd( s, FILE_READ_DATA, NULL );
/* block here */
do_block(fd, POLLIN, -1);
_sync_sock_state(s); /* let wineserver notice connection */
release_sock_fd( s, fd );
} }
error: TRACE("returning %#lx\n", ret);
WARN(" -> ERROR %d\n", err); return ret;
SetLastError(err);
return INVALID_SOCKET;
} }
/*********************************************************************** /***********************************************************************
......
...@@ -542,6 +542,11 @@ struct iosb *async_get_iosb( struct async *async ) ...@@ -542,6 +542,11 @@ struct iosb *async_get_iosb( struct async *async )
return async->iosb ? (struct iosb *)grab_object( async->iosb ) : NULL; return async->iosb ? (struct iosb *)grab_object( async->iosb ) : NULL;
} }
struct thread *async_get_thread( struct async *async )
{
return async->thread;
}
int async_is_blocking( struct async *async ) int async_is_blocking( struct async *async )
{ {
return !async->event && !async->data.apc && !async->data.apc_context; return !async->event && !async->data.apc && !async->data.apc_context;
......
...@@ -221,6 +221,7 @@ extern struct completion *fd_get_completion( struct fd *fd, apc_param_t *p_key ) ...@@ -221,6 +221,7 @@ extern struct completion *fd_get_completion( struct fd *fd, apc_param_t *p_key )
extern void fd_copy_completion( struct fd *src, struct fd *dst ); extern void fd_copy_completion( struct fd *src, struct fd *dst );
extern struct iosb *create_iosb( const void *in_data, data_size_t in_size, data_size_t out_size ); extern struct iosb *create_iosb( const void *in_data, data_size_t in_size, data_size_t out_size );
extern struct iosb *async_get_iosb( struct async *async ); extern struct iosb *async_get_iosb( struct async *async );
extern struct thread *async_get_thread( struct async *async );
extern int async_is_blocking( struct async *async ); extern int async_is_blocking( struct async *async );
extern struct async *find_pending_async( struct async_queue *queue ); extern struct async *find_pending_async( struct async_queue *queue );
extern void cancel_process_asyncs( struct process *process ); extern void cancel_process_asyncs( struct process *process );
......
...@@ -175,6 +175,7 @@ static void sock_queue_async( struct fd *fd, struct async *async, int type, int ...@@ -175,6 +175,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 void sock_reselect_async( struct fd *fd, struct async_queue *queue );
static int accept_into_socket( struct sock *sock, struct sock *acceptsock ); static int accept_into_socket( struct sock *sock, struct sock *acceptsock );
static struct sock *accept_socket( struct sock *sock );
static int sock_get_ntstatus( int err ); static int sock_get_ntstatus( int err );
static unsigned int sock_get_error( int err ); static unsigned int sock_get_error( int err );
...@@ -448,7 +449,7 @@ static inline int sock_error( struct fd *fd ) ...@@ -448,7 +449,7 @@ static inline int sock_error( struct fd *fd )
static void free_accept_req( struct accept_req *req ) static void free_accept_req( struct accept_req *req )
{ {
list_remove( &req->entry ); list_remove( &req->entry );
req->acceptsock->accept_recv_req = NULL; if (req->acceptsock) req->acceptsock->accept_recv_req = NULL;
release_object( req->async ); release_object( req->async );
free( req ); free( req );
} }
...@@ -527,11 +528,37 @@ static void complete_async_accept( struct sock *sock, struct accept_req *req ) ...@@ -527,11 +528,37 @@ static void complete_async_accept( struct sock *sock, struct accept_req *req )
if (debug_level) fprintf( stderr, "completing accept request for socket %p\n", sock ); if (debug_level) fprintf( stderr, "completing accept request for socket %p\n", sock );
if (!accept_into_socket( sock, acceptsock )) return; if (acceptsock)
{
if (!accept_into_socket( sock, acceptsock )) return;
iosb = async_get_iosb( async ); iosb = async_get_iosb( async );
fill_accept_output( req, iosb ); fill_accept_output( req, iosb );
release_object( iosb ); release_object( iosb );
}
else
{
obj_handle_t handle;
if (!(acceptsock = accept_socket( sock ))) return;
handle = alloc_handle_no_access_check( async_get_thread( async )->process, &acceptsock->obj,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, OBJ_INHERIT );
acceptsock->wparam = handle;
release_object( acceptsock );
if (!handle) return;
iosb = async_get_iosb( async );
if (!(iosb->out_data = malloc( sizeof(handle) )))
{
release_object( iosb );
return;
}
iosb->status = STATUS_SUCCESS;
iosb->out_size = sizeof(handle);
memcpy( iosb->out_data, &handle, sizeof(handle) );
release_object( iosb );
set_error( STATUS_ALERTED );
}
} }
static void complete_async_accept_recv( struct accept_req *req ) static void complete_async_accept_recv( struct accept_req *req )
...@@ -1344,8 +1371,11 @@ static struct accept_req *alloc_accept_req( struct sock *acceptsock, struct asyn ...@@ -1344,8 +1371,11 @@ static struct accept_req *alloc_accept_req( struct sock *acceptsock, struct asyn
req->accepted = 0; req->accepted = 0;
req->recv_len = 0; req->recv_len = 0;
req->local_len = 0; req->local_len = 0;
req->recv_len = params->recv_len; if (params)
req->local_len = params->local_len; {
req->recv_len = params->recv_len;
req->local_len = params->local_len;
}
} }
return req; return req;
} }
...@@ -1384,7 +1414,21 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) ...@@ -1384,7 +1414,21 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
return 0; return 0;
} }
if (!(acceptsock = accept_socket( sock ))) return 0; if (!(acceptsock = accept_socket( sock )))
{
struct accept_req *req;
if (sock->state & FD_WINE_NONBLOCKING) return 0;
if (get_error() != (0xc0010000 | WSAEWOULDBLOCK)) return 0;
if (!(req = alloc_accept_req( NULL, async, NULL ))) return 0;
list_add_tail( &sock->accept_list, &req->entry );
queue_async( &sock->accept_q, async );
sock_reselect( sock );
set_error( STATUS_PENDING );
return 1;
}
handle = alloc_handle( current->process, &acceptsock->obj, handle = alloc_handle( current->process, &acceptsock->obj,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, OBJ_INHERIT ); GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, OBJ_INHERIT );
acceptsock->wparam = handle; acceptsock->wparam = handle;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment