From: Rémi Bernon rbernon@codeweavers.com
--- server/fd.c | 2 +- server/file.c | 2 +- server/inproc_sync.c | 2 +- server/process.c | 4 ++-- server/protocol.def | 6 ++++++ server/request.c | 30 +++++++++++++++++++++++++++--- server/request.h | 4 ++-- server/thread.c | 40 ++++++++++++++++++++++++++-------------- server/thread.h | 9 +++++---- 9 files changed, 71 insertions(+), 28 deletions(-)
diff --git a/server/fd.c b/server/fd.c index 1b932cc3ae3..fcd6ac85674 100644 --- a/server/fd.c +++ b/server/fd.c @@ -2893,7 +2893,7 @@ DECL_HANDLER(get_handle_fd) reply->type = fd->fd_ops->get_fd_type( fd ); reply->options = fd->options; reply->access = get_handle_access( current->process, req->handle ); - send_client_fd( current->process, unix_fd, req->handle ); + send_client_fd( current->process, FD_TYPE_UNIX, unix_fd, req->handle ); } release_object( fd ); } diff --git a/server/file.c b/server/file.c index cc5acc2aadc..c9dc2c07485 100644 --- a/server/file.c +++ b/server/file.c @@ -680,7 +680,7 @@ DECL_HANDLER(alloc_file_handle) int fd;
reply->handle = 0; - if ((fd = thread_get_inflight_fd( current, req->fd )) == -1) + if ((fd = thread_get_inflight_fd( current, FD_TYPE_UNIX, req->fd )) == -1) { set_error( STATUS_INVALID_HANDLE ); return; diff --git a/server/inproc_sync.c b/server/inproc_sync.c index f20410c85ed..eff2ed47f19 100644 --- a/server/inproc_sync.c +++ b/server/inproc_sync.c @@ -184,7 +184,7 @@ DECL_HANDLER(get_inproc_sync_fd) reply->access = get_handle_access( current->process, req->handle );
if ((fd = get_inproc_sync_fd( obj, &reply->type )) < 0) set_error( STATUS_NOT_IMPLEMENTED ); - else send_client_fd( current->process, fd, req->handle ); + else send_client_fd( current->process, FD_TYPE_UNIX, fd, req->handle );
release_object( obj ); } diff --git a/server/process.c b/server/process.c index 8e0f9189a61..ec1ce0967ad 100644 --- a/server/process.c +++ b/server/process.c @@ -881,7 +881,7 @@ static void process_poll_event( struct fd *fd, int event ) assert( process->obj.ops == &process_ops );
if (event & (POLLERR | POLLHUP)) kill_process( process, !process->is_terminating ); - else if (event & POLLIN) receive_fd( process ); + else if (event & POLLIN) receive_fd( process, FD_TYPE_UNIX ); }
static void startup_info_destroy( struct object *obj ) @@ -1160,7 +1160,7 @@ DECL_HANDLER(new_process) struct debug_obj *debug_obj = NULL; struct process *parent; struct thread *parent_thread = current; - int socket_fd = thread_get_inflight_fd( current, req->socket_fd ); + int socket_fd = thread_get_inflight_fd( current, FD_TYPE_UNIX, req->socket_fd ); const obj_handle_t *handles = NULL; const obj_handle_t *job_handles = NULL; unsigned int i, job_handle_count; diff --git a/server/protocol.def b/server/protocol.def index 59c6436fa88..8966deeb78e 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -61,6 +61,12 @@ struct reply_header data_size_t reply_size; /* reply variable part size */ };
+enum fd_type +{ + FD_TYPE_NONE = 0, + FD_TYPE_UNIX = 1, +}; + /* placeholder structure for the maximum allowed request size */ /* this is used to construct the generic_request union */ struct request_max_size diff --git a/server/request.c b/server/request.c index 835ea30cec3..da941c9b59d 100644 --- a/server/request.c +++ b/server/request.c @@ -374,7 +374,7 @@ error: }
/* receive a file descriptor on the process socket */ -int receive_fd( struct process *process ) +static int receive_unix_fd( struct process *process ) { struct iovec vec; struct send_fd data; @@ -424,7 +424,7 @@ int receive_fd( struct process *process ) if (debug_level) fprintf( stderr, "%04x: *fd* %d <- %d\n", thread->id, data.fd, fd ); - thread_add_inflight_fd( thread, data.fd, fd ); + thread_add_inflight_fd( thread, FD_TYPE_UNIX, data.fd, fd ); } if (thread) release_object( thread ); return 0; @@ -454,7 +454,7 @@ int receive_fd( struct process *process ) }
/* send an fd to a client */ -int send_client_fd( struct process *process, int fd, obj_handle_t handle ) +static int send_unix_fd( struct process *process, int fd, obj_handle_t handle ) { struct iovec vec; struct msghdr msghdr; @@ -505,6 +505,30 @@ int send_client_fd( struct process *process, int fd, obj_handle_t handle ) return -1; }
+int receive_fd( struct process *process, enum fd_type type ) +{ + switch (type) + { + case FD_TYPE_NONE: return 0; + case FD_TYPE_UNIX: return receive_unix_fd( process ); + default: assert( 0 ); break; + } +} + +int send_client_fd( struct process *process, enum fd_type type, int fd, obj_handle_t handle ) +{ + int ret = -1; + + switch (type) + { + case FD_TYPE_NONE: ret = 0; break; + case FD_TYPE_UNIX: ret = send_unix_fd( process, fd, handle ); break; + default: assert( 0 ); break; + } + + return ret; +} + /* return a monotonic time counter */ timeout_t monotonic_counter(void) { diff --git a/server/request.h b/server/request.h index 13254d967ed..9d9d106d54a 100644 --- a/server/request.h +++ b/server/request.h @@ -50,8 +50,8 @@ extern const struct object_attributes *get_req_object_attributes( const struct s struct unicode_str *name, struct object **root ); extern const void *get_req_data_after_objattr( const struct object_attributes *attr, data_size_t *len ); -extern int receive_fd( struct process *process ); -extern int send_client_fd( struct process *process, int fd, obj_handle_t handle ); +extern int receive_fd( struct process *process, enum fd_type type ); +extern int send_client_fd( struct process *process, enum fd_type type, int fd, obj_handle_t handle ); extern void read_request( struct thread *thread ); extern void write_reply( struct thread *thread ); extern timeout_t monotonic_counter(void); diff --git a/server/thread.c b/server/thread.c index 93b77f6b36e..48c0cf16090 100644 --- a/server/thread.c +++ b/server/thread.c @@ -391,9 +391,20 @@ static void apply_thread_priority( struct thread *thread, int effective_priority
#endif
+static void close_fd_type( enum fd_type type, int fd ) +{ + switch (type) + { + case FD_TYPE_NONE: break; + case FD_TYPE_UNIX: close( fd ); break; + default: assert( 0 ); break; + } +} + static void clear_inflight_fd( struct inflight_fd *fd, int need_close ) { - if (need_close) close( fd->server ); + if (need_close) close_fd_type( fd->type, fd->server ); + fd->type = FD_TYPE_NONE; fd->client = fd->server = -1; }
@@ -515,7 +526,7 @@ struct thread *create_thread( int fd, struct process *process, const struct secu file_set_error(); return NULL; } - if (send_client_fd( process, request_pipe[1], SERVER_PROTOCOL_VERSION ) == -1) + if (send_client_fd( process, FD_TYPE_UNIX, request_pipe[1], SERVER_PROTOCOL_VERSION ) == -1) { close( request_pipe[0] ); close( request_pipe[1] ); @@ -1504,20 +1515,20 @@ static void clear_apc_queue( struct list *queue ) }
/* add an fd to the inflight list */ -void thread_add_inflight_fd( struct thread *thread, int client, int server ) +void thread_add_inflight_fd( struct thread *thread, enum fd_type type, int client, int server ) { - struct inflight_fd *fd, new = { .client = client, .server = server }; + struct inflight_fd *fd, new = { .type = type, .client = client, .server = server };
if (client == -1) clear_inflight_fd( &new, 1 ); - if (server == -1) return; + if (server == -1 || type == FD_TYPE_NONE) return;
/* first check if we already have an entry for this fd */ for (fd = thread->inflight; fd < thread->inflight + MAX_INFLIGHT_FDS; fd++) - if (fd->client == new.client) goto done; + if (fd->type == new.type && fd->client == new.client) goto done;
/* now find a free spot to store it */ for (fd = thread->inflight; fd < thread->inflight + MAX_INFLIGHT_FDS; fd++) - if (fd->client == -1) goto done; + if (fd->type == FD_TYPE_NONE) goto done;
fatal_error( "%04x: inflight fd array is full\n", thread->id );
@@ -1528,24 +1539,25 @@ done:
/* get an inflight fd and purge it from the list */ /* the fd must be closed when no longer used */ -int thread_get_inflight_fd( struct thread *thread, int client ) +int thread_get_inflight_fd( struct thread *thread, enum fd_type type, int client ) { struct inflight_fd *fd;
+ if (type == FD_TYPE_NONE) return 0; if (client == -1) return -1;
do { for (fd = thread->inflight; fd < thread->inflight + MAX_INFLIGHT_FDS; fd++) { - if (fd->client == client) + if (fd->type == type && fd->client == client) { int ret = fd->server; clear_inflight_fd( fd, 0 ); return ret; } } - } while (!receive_fd( thread->process )); /* in case it is still in the socket buffer */ + } while (!receive_fd( thread->process, type )); /* in case it is still in the socket buffer */ return -1; }
@@ -1606,7 +1618,7 @@ DECL_HANDLER(new_thread) struct unicode_str name; const struct security_descriptor *sd; const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, NULL ); - int request_fd = thread_get_inflight_fd( current, req->request_fd ); + int request_fd = thread_get_inflight_fd( current, FD_TYPE_UNIX, req->request_fd );
if (!(process = get_process_from_handle( req->process, 0 ))) { @@ -1662,12 +1674,12 @@ done:
static int init_thread( struct thread *thread, int reply_fd, int wait_fd ) { - if ((reply_fd = thread_get_inflight_fd( thread, reply_fd )) == -1) + if ((reply_fd = thread_get_inflight_fd( thread, FD_TYPE_UNIX, reply_fd )) == -1) { set_error( STATUS_TOO_MANY_OPENED_FILES ); return 0; } - if ((wait_fd = thread_get_inflight_fd( thread, wait_fd )) == -1) + if ((wait_fd = thread_get_inflight_fd( thread, FD_TYPE_UNIX, wait_fd )) == -1) { set_error( STATUS_TOO_MANY_OPENED_FILES ); goto error; @@ -1722,7 +1734,7 @@ DECL_HANDLER(init_first_thread) if ((fd = get_inproc_device_fd()) >= 0) { reply->inproc_device = get_process_id( process ) | 1; - send_client_fd( process, fd, reply->inproc_device ); + send_client_fd( process, FD_TYPE_UNIX, fd, reply->inproc_device ); } }
diff --git a/server/thread.h b/server/thread.h index cf9bdf02e65..6a22fa85d02 100644 --- a/server/thread.h +++ b/server/thread.h @@ -42,8 +42,9 @@ enum run_state /* descriptor for fds currently in flight from client to server */ struct inflight_fd { - int client; /* fd on the client side (or -1 if entry is free) */ - int server; /* fd on the server side */ + enum fd_type type; /* fd type, FD_TYPE_NONE if entry is free */ + int client; /* fd on the client side */ + int server; /* fd on the server side */ }; #define MAX_INFLIGHT_FDS 16 /* max number of fds in flight per thread */
@@ -123,8 +124,8 @@ extern void kill_thread( struct thread *thread, int violent_death ); extern void wake_up( struct object *obj, int max ); extern int thread_queue_apc( struct process *process, struct thread *thread, struct object *owner, const union apc_call *call_data ); extern void thread_cancel_apc( struct thread *thread, struct object *owner, enum apc_type type ); -extern void thread_add_inflight_fd( struct thread *thread, int client, int server ); -extern int thread_get_inflight_fd( struct thread *thread, int client ); +extern void thread_add_inflight_fd( struct thread *thread, enum fd_type type, int client, int server ); +extern int thread_get_inflight_fd( struct thread *thread, enum fd_type type, int client ); extern struct token *thread_get_impersonation_token( struct thread *thread ); extern unsigned int set_thread_priority( struct thread *thread, int priority ); extern unsigned int set_thread_base_priority( struct thread *thread, int base_priority );