From 96593370cd7b1ec127270a1c4a95d055baf532c8 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 1 Sep 2021 17:28:38 -0500 Subject: [PATCH] server: Introduce a helper to fill an iosb and terminate the async. For convenience, and to centralize the STATUS_ALERTED logic into one place. Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard --- server/async.c | 29 +++++++++++ server/console.c | 51 +++++++------------ server/device.c | 14 ++--- server/file.h | 2 + server/named_pipe.c | 4 +- server/sock.c | 121 +++++++++++++++++++------------------------- 6 files changed, 105 insertions(+), 116 deletions(-) diff --git a/server/async.c b/server/async.c index d45f234144d..e71dceb201b 100644 --- a/server/async.c +++ b/server/async.c @@ -332,6 +332,35 @@ obj_handle_t async_handoff( struct async *async, int success, data_size_t *resul return async->wait_handle; } +/* complete a request-based async with a pre-allocated buffer */ +void async_request_complete( struct async *async, unsigned int status, data_size_t result, + data_size_t out_size, void *out_data ) +{ + struct iosb *iosb = async_get_iosb( async ); + + /* the async may have already been canceled */ + if (iosb->status != STATUS_PENDING) + { + release_object( iosb ); + free( out_data ); + return; + } + + iosb->status = status; + iosb->result = result; + iosb->out_data = out_data; + iosb->out_size = out_size; + + release_object( iosb ); + + /* if the result is nonzero or there is output data, the client needs to + * make an extra request to retrieve them; use STATUS_ALERTED to signal + * this case */ + if (result || out_data) + status = STATUS_ALERTED; + async_terminate( async, status ); +} + /* set the timeout of an async operation */ void async_set_timeout( struct async *async, timeout_t timeout, unsigned int status ) { diff --git a/server/console.c b/server/console.c index 1e6f6c0f8a3..94f7c37e7c5 100644 --- a/server/console.c +++ b/server/console.c @@ -976,7 +976,6 @@ static int console_flush( struct fd *fd, struct async *async ) static int screen_buffer_write( struct fd *fd, struct async *async, file_pos_t pos ) { struct screen_buffer *screen_buffer = get_fd_user( fd ); - struct iosb *iosb; if (!screen_buffer->input || !screen_buffer->input->server) { @@ -984,16 +983,8 @@ static int screen_buffer_write( struct fd *fd, struct async *async, file_pos_t p return 0; } - if (!queue_host_ioctl( screen_buffer->input->server, IOCTL_CONDRV_WRITE_FILE, - screen_buffer->id, async, &screen_buffer->ioctl_q )) - return 0; - - /* we can't use default async handling, because write result is not - * compatible with ioctl result */ - iosb = async_get_iosb( async ); - iosb->result = iosb->in_size; - release_object( iosb ); - return 1; + return queue_host_ioctl( screen_buffer->input->server, IOCTL_CONDRV_WRITE_FILE, + screen_buffer->id, async, &screen_buffer->ioctl_q ); } static int screen_buffer_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) @@ -1498,36 +1489,28 @@ DECL_HANDLER(get_next_console_request) if (ioctl) { + struct async *async = ioctl->async; unsigned int status = req->status; + if (status == STATUS_PENDING) status = STATUS_INVALID_PARAMETER; - if (ioctl->async) + if (async) { - iosb = async_get_iosb( ioctl->async ); + iosb = async_get_iosb( async ); if (iosb->status == STATUS_PENDING) { - iosb->status = status; - iosb->out_size = min( iosb->out_size, get_req_data_size() ); - if (iosb->out_size) - { - if ((iosb->out_data = memdup( get_req_data(), iosb->out_size ))) - { - iosb->result = iosb->out_size; - } - else if (!status) - { - iosb->status = STATUS_NO_MEMORY; - iosb->out_size = 0; - } - } - if (iosb->result) status = STATUS_ALERTED; - } - else - { - release_object( ioctl->async ); - ioctl->async = NULL; + data_size_t out_size = min( iosb->out_size, get_req_data_size() ); + data_size_t result = ioctl->code == IOCTL_CONDRV_WRITE_FILE ? iosb->in_size : out_size; + void *out_data; + + if (!out_size || (out_data = memdup( get_req_data(), out_size ))) + async_request_complete( async, status, result, out_size, out_data ); + else + async_terminate( async, STATUS_NO_MEMORY ); } + + release_object( async ); } - console_host_ioctl_terminate( ioctl, status ); + free( ioctl ); if (iosb) release_object( iosb ); if (req->read) diff --git a/server/device.c b/server/device.c index a89c03f0fb0..96389a1459b 100644 --- a/server/device.c +++ b/server/device.c @@ -385,16 +385,12 @@ static void set_irp_result( struct irp_call *irp, unsigned int status, irp->file = NULL; if (irp->async) { - struct iosb *iosb = irp->iosb; + void *out_data; - iosb->status = status; - iosb->result = result; - iosb->out_size = min( iosb->out_size, out_size ); - if (iosb->out_size && !(iosb->out_data = memdup( out_data, iosb->out_size ))) - iosb->out_size = 0; - - if (result) status = STATUS_ALERTED; - async_terminate( irp->async, status ); + out_size = min( irp->iosb->out_size, out_size ); + if (out_size && !(out_data = memdup( out_data, out_size ))) + out_size = 0; + async_request_complete( irp->async, status, result, out_size, out_data ); release_object( irp->async ); irp->async = NULL; } diff --git a/server/file.h b/server/file.h index f6c5832a733..1c019a0667e 100644 --- a/server/file.h +++ b/server/file.h @@ -227,6 +227,8 @@ extern void async_set_completion_callback( struct async *async, async_completion extern void set_async_pending( struct async *async, int signal ); extern int async_waiting( struct async_queue *queue ); extern void async_terminate( struct async *async, unsigned int status ); +extern void async_request_complete( struct async *async, unsigned int status, data_size_t result, + data_size_t out_size, void *out_data ); extern void async_wake_up( struct async_queue *queue, unsigned int status ); 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 ); diff --git a/server/named_pipe.c b/server/named_pipe.c index df8c7e3170c..da3485dd2bc 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -390,9 +390,7 @@ static void wake_message( struct pipe_message *message, data_size_t result ) message->async = NULL; if (!async) return; - message->iosb->status = STATUS_SUCCESS; - message->iosb->result = result; - async_terminate( async, message->iosb->result ? STATUS_ALERTED : STATUS_SUCCESS ); + async_request_complete( async, STATUS_SUCCESS, result, 0, NULL ); release_object( async ); } diff --git a/server/sock.c b/server/sock.c index 50bfc08e145..00d5d47edff 100644 --- a/server/sock.c +++ b/server/sock.c @@ -623,7 +623,8 @@ static void free_accept_req( void *private ) static void fill_accept_output( struct accept_req *req ) { - struct iosb *iosb = req->iosb; + const data_size_t out_size = req->iosb->out_size; + struct async *async = req->async; union unix_sockaddr unix_addr; struct WS_sockaddr *win_addr; unsigned int remote_len; @@ -632,7 +633,11 @@ static void fill_accept_output( struct accept_req *req ) char *out_data; int win_len; - if (!(out_data = mem_alloc( iosb->out_size ))) return; + if (!(out_data = mem_alloc( out_size ))) + { + async_terminate( async, get_error() ); + return; + } fd = get_unix_fd( req->acceptsock->fd ); @@ -642,11 +647,10 @@ static void fill_accept_output( struct accept_req *req ) { req->accepted = 1; sock_reselect( req->acceptsock ); - set_error( STATUS_PENDING ); return; } - set_error( sock_get_ntstatus( errno ) ); + async_terminate( async, sock_get_ntstatus( errno ) ); free( out_data ); return; } @@ -655,7 +659,7 @@ static void fill_accept_output( struct accept_req *req ) { if (req->local_len < sizeof(int)) { - set_error( STATUS_BUFFER_TOO_SMALL ); + async_terminate( async, STATUS_BUFFER_TOO_SMALL ); free( out_data ); return; } @@ -665,7 +669,7 @@ static void fill_accept_output( struct accept_req *req ) if (getsockname( fd, &unix_addr.addr, &unix_len ) < 0 || (win_len = sockaddr_from_unix( &unix_addr, win_addr, req->local_len - sizeof(int) )) < 0) { - set_error( sock_get_ntstatus( errno ) ); + async_terminate( async, sock_get_ntstatus( errno ) ); free( out_data ); return; } @@ -674,20 +678,17 @@ static void fill_accept_output( struct accept_req *req ) unix_len = sizeof(unix_addr); win_addr = (struct WS_sockaddr *)(out_data + req->recv_len + req->local_len + sizeof(int)); - remote_len = iosb->out_size - req->recv_len - req->local_len; + remote_len = out_size - req->recv_len - req->local_len; if (getpeername( fd, &unix_addr.addr, &unix_len ) < 0 || (win_len = sockaddr_from_unix( &unix_addr, win_addr, remote_len - sizeof(int) )) < 0) { - set_error( sock_get_ntstatus( errno ) ); + async_terminate( async, sock_get_ntstatus( errno ) ); free( out_data ); return; } memcpy( out_data + req->recv_len + req->local_len, &win_len, sizeof(int) ); - iosb->status = STATUS_SUCCESS; - iosb->result = size; - iosb->out_data = out_data; - set_error( STATUS_ALERTED ); + async_request_complete( req->async, STATUS_SUCCESS, size, out_size, out_data ); } static void complete_async_accept( struct sock *sock, struct accept_req *req ) @@ -699,27 +700,37 @@ static void complete_async_accept( struct sock *sock, struct accept_req *req ) if (acceptsock) { - if (!accept_into_socket( sock, acceptsock )) return; + if (!accept_into_socket( sock, acceptsock )) + { + async_terminate( async, get_error() ); + return; + } fill_accept_output( req ); } else { - struct iosb *iosb = req->iosb; obj_handle_t handle; + void *out_data; - if (!(acceptsock = accept_socket( sock ))) return; + if (!(acceptsock = accept_socket( sock ))) + { + async_terminate( async, get_error() ); + 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; + if (!handle) + { + async_terminate( async, get_error() ); + return; + } - if (!(iosb->out_data = malloc( sizeof(handle) ))) return; + if (!(out_data = malloc( sizeof(handle) ))) return; - iosb->status = STATUS_SUCCESS; - iosb->out_size = sizeof(handle); - memcpy( iosb->out_data, &handle, sizeof(handle) ); - set_error( STATUS_ALERTED ); + memcpy( out_data, &handle, sizeof(handle) ); + async_request_complete( req->async, STATUS_SUCCESS, 0, sizeof(handle), out_data ); } } @@ -747,7 +758,6 @@ static void complete_async_connect( struct sock *sock ) { struct connect_req *req = sock->connect_req; const char *in_buffer; - struct iosb *iosb; size_t len; int ret; @@ -757,28 +767,20 @@ static void complete_async_connect( struct sock *sock ) if (!req->send_len) { - set_error( STATUS_SUCCESS ); + async_terminate( req->async, STATUS_SUCCESS ); return; } - iosb = req->iosb; - in_buffer = (const char *)iosb->in_data + sizeof(struct afd_connect_params) + req->addr_len; + in_buffer = (const char *)req->iosb->in_data + sizeof(struct afd_connect_params) + req->addr_len; len = req->send_len - req->send_cursor; ret = send( get_unix_fd( sock->fd ), in_buffer + req->send_cursor, len, 0 ); if (ret < 0 && errno != EWOULDBLOCK) - set_error( sock_get_ntstatus( errno ) ); + async_terminate( req->async, sock_get_ntstatus( errno ) ); else if (ret == len) - { - iosb->result = req->send_len; - iosb->status = STATUS_SUCCESS; - set_error( STATUS_ALERTED ); - } + async_request_complete( req->async, STATUS_SUCCESS, req->send_len, 0, NULL ); else - { req->send_cursor += ret; - set_error( STATUS_PENDING ); - } } static void free_poll_req( void *private ) @@ -840,10 +842,9 @@ static void complete_async_polls( struct sock *sock, int event, int error ) LIST_FOR_EACH_ENTRY_SAFE( req, next, &poll_list, struct poll_req, entry ) { - struct iosb *iosb = req->iosb; unsigned int i; - if (iosb->status != STATUS_PENDING) continue; + if (req->iosb->status != STATUS_PENDING) continue; for (i = 0; i < req->count; ++i) { @@ -857,10 +858,8 @@ static void complete_async_polls( struct sock *sock, int event, int error ) req->output[i].flags = req->sockets[i].flags & flags; req->output[i].status = sock_get_ntstatus( error ); - iosb->status = STATUS_SUCCESS; - iosb->out_data = req->output; - iosb->out_size = req->count * sizeof(*req->output); - async_terminate( req->async, STATUS_ALERTED ); + async_request_complete( req->async, STATUS_SUCCESS, 0, + req->count * sizeof(*req->output), req->output ); break; } } @@ -869,16 +868,12 @@ static void complete_async_polls( struct sock *sock, int event, int error ) static void async_poll_timeout( void *private ) { struct poll_req *req = private; - struct iosb *iosb = req->iosb; req->timeout = NULL; - if (iosb->status != STATUS_PENDING) return; + if (req->iosb->status != STATUS_PENDING) return; - iosb->status = STATUS_TIMEOUT; - iosb->out_data = req->output; - iosb->out_size = req->count * sizeof(*req->output); - async_terminate( req->async, STATUS_ALERTED ); + async_request_complete( req->async, STATUS_TIMEOUT, 0, req->count * sizeof(*req->output), req->output ); } static int sock_dispatch_asyncs( struct sock *sock, int event, int error ) @@ -892,26 +887,16 @@ static int sock_dispatch_asyncs( struct sock *sock, int event, int error ) if (req->iosb->status == STATUS_PENDING && !req->accepted) { complete_async_accept( sock, req ); - if (get_error() != STATUS_PENDING) - async_terminate( req->async, get_error() ); break; } } if (sock->accept_recv_req && sock->accept_recv_req->iosb->status == STATUS_PENDING) - { complete_async_accept_recv( sock->accept_recv_req ); - if (get_error() != STATUS_PENDING) - async_terminate( sock->accept_recv_req->async, get_error() ); - } } if ((event & POLLOUT) && sock->connect_req && sock->connect_req->iosb->status == STATUS_PENDING) - { complete_async_connect( sock ); - if (get_error() != STATUS_PENDING) - async_terminate( sock->connect_req->async, get_error() ); - } if (event & (POLLIN | POLLPRI) && async_waiting( &sock->read_q )) { @@ -1323,6 +1308,7 @@ static int sock_close_handle( struct object *obj, struct process *process, obj_h LIST_FOR_EACH_ENTRY_SAFE( poll_req, poll_next, &poll_list, struct poll_req, entry ) { struct iosb *iosb = poll_req->iosb; + BOOL signaled = FALSE; unsigned int i; if (iosb->status != STATUS_PENDING) continue; @@ -1331,17 +1317,17 @@ static int sock_close_handle( struct object *obj, struct process *process, obj_h { if (poll_req->sockets[i].sock == sock) { - iosb->status = STATUS_SUCCESS; + signaled = TRUE; poll_req->output[i].flags = AFD_POLL_CLOSE; poll_req->output[i].status = 0; } } - if (iosb->status != STATUS_PENDING) + if (signaled) { - iosb->out_data = poll_req->output; - iosb->out_size = poll_req->count * sizeof(*poll_req->output); - async_terminate( poll_req->async, STATUS_ALERTED ); + /* pass 0 as result; client will set actual result size */ + async_request_complete( poll_req->async, STATUS_SUCCESS, 0, + poll_req->count * sizeof(*poll_req->output), poll_req->output ); } } } @@ -2857,6 +2843,7 @@ static int poll_socket( struct sock *poll_sock, struct async *async, timeout_t t unsigned int count, const struct poll_socket_input *input ) { struct poll_socket_output *output; + BOOL signaled = FALSE; struct poll_req *req; unsigned int i, j; @@ -2902,8 +2889,6 @@ static int poll_socket( struct sock *poll_sock, struct async *async, timeout_t t async_set_completion_callback( async, free_poll_req, req ); queue_async( &poll_sock->poll_q, async ); - if (!timeout) req->iosb->status = STATUS_SUCCESS; - for (i = 0; i < count; ++i) { struct sock *sock = req->sockets[i].sock; @@ -2912,7 +2897,7 @@ static int poll_socket( struct sock *poll_sock, struct async *async, timeout_t t if (flags) { - req->iosb->status = STATUS_SUCCESS; + signaled = TRUE; output[i].flags = flags; output[i].status = sock_get_ntstatus( sock_error( sock->fd ) ); } @@ -2926,12 +2911,8 @@ static int poll_socket( struct sock *poll_sock, struct async *async, timeout_t t } } - if (req->iosb->status != STATUS_PENDING) - { - req->iosb->out_data = output; - req->iosb->out_size = count * sizeof(*output); - async_terminate( req->async, STATUS_ALERTED ); - } + if (!timeout || signaled) + async_request_complete( req->async, STATUS_SUCCESS, 0, count * sizeof(*output), output ); for (i = 0; i < req->count; ++i) sock_reselect( req->sockets[i].sock );