Use a separate FIFO pair for server requests that don't need to pass a
file descriptor.
Associate file descriptors with handles on the server side so that we
don't need to pass the fd every time the client wants to use it.
diff --git a/server/request.c b/server/request.c
index c3928e5..fff02dd4 100644
--- a/server/request.c
+++ b/server/request.c
@@ -71,6 +71,32 @@
};
+struct request_socket
+{
+ struct object obj; /* object header */
+ struct thread *thread; /* owning thread */
+};
+
+static void request_socket_dump( struct object *obj, int verbose );
+static void request_socket_poll_event( struct object *obj, int event );
+
+static const struct object_ops request_socket_ops =
+{
+ sizeof(struct request_socket), /* size */
+ request_socket_dump, /* dump */
+ no_add_queue, /* add_queue */
+ NULL, /* remove_queue */
+ NULL, /* signaled */
+ NULL, /* satisfied */
+ NULL, /* get_poll_events */
+ request_socket_poll_event, /* poll_event */
+ no_get_fd, /* get_fd */
+ no_flush, /* flush */
+ no_get_file_info, /* get_file_info */
+ no_destroy /* destroy */
+};
+
+
struct thread *current = NULL; /* thread handling the current request */
unsigned int global_error = 0; /* global error code for when no thread is current */
@@ -149,13 +175,6 @@
fatal_protocol_error( current, "bad request %d\n", req );
}
-/* set the fd to pass to the thread */
-void set_reply_fd( struct thread *thread, int pass_fd )
-{
- assert( thread->pass_fd == -1 );
- thread->pass_fd = pass_fd;
-}
-
/* send a reply to a thread */
void send_reply( struct thread *thread )
{
@@ -213,29 +232,9 @@
header->error = thread->error;
- if (thread->pass_fd == -1)
- {
- /* write a single byte; the value is ignored anyway */
- ret = write( thread->obj.fd, header, 1 );
- }
- else /* we have an fd to send */
- {
-#ifdef HAVE_MSGHDR_ACCRIGHTS
- msghdr.msg_accrightslen = sizeof(int);
- msghdr.msg_accrights = (void *)&thread->pass_fd;
-#else /* HAVE_MSGHDR_ACCRIGHTS */
- msghdr.msg_control = &cmsg;
- msghdr.msg_controllen = sizeof(cmsg);
- cmsg.fd = thread->pass_fd;
-#endif /* HAVE_MSGHDR_ACCRIGHTS */
+ assert (thread->pass_fd == -1);
- myiovec.iov_base = (void *)header;
- myiovec.iov_len = 1;
-
- ret = sendmsg( thread->obj.fd, &msghdr, 0 );
- close( thread->pass_fd );
- thread->pass_fd = -1;
- }
+ ret = write( thread->reply_fd, header, 1 );
if (ret > 0)
{
set_select_events( &thread->obj, POLLIN );
@@ -255,6 +254,40 @@
return -1;
}
+/* send an fd to a client */
+int send_client_fd( struct thread *thread, int fd, int handle )
+{
+ int ret;
+
+#ifdef HAVE_MSGHDR_ACCRIGHTS
+ msghdr.msg_accrightslen = sizeof(fd);
+ msghdr.msg_accrights = (void *)&fd;
+#else /* HAVE_MSGHDR_ACCRIGHTS */
+ msghdr.msg_control = &cmsg;
+ msghdr.msg_controllen = sizeof(cmsg);
+ cmsg.fd = fd;
+#endif /* HAVE_MSGHDR_ACCRIGHTS */
+
+ myiovec.iov_base = (void *)&handle;
+ myiovec.iov_len = sizeof(handle);
+
+ ret = sendmsg( thread->obj.fd, &msghdr, 0 );
+ close( fd );
+
+ if (ret > 0) return 0;
+ if (errno == EPIPE)
+ {
+ kill_thread( thread, 0 ); /* normal death */
+ }
+ else
+ {
+ perror("sendmsg");
+ thread->exit_code = 1;
+ kill_thread( thread, 1 );
+ }
+ return -1;
+}
+
static void master_socket_dump( struct object *obj, int verbose )
{
struct master_socket *sock = (struct master_socket *)obj;
@@ -297,6 +330,61 @@
socket_cleanup();
}
+static void request_socket_dump( struct object *obj, int verbose )
+{
+ struct request_socket *sock = (struct request_socket *)obj;
+ assert( obj->ops == &request_socket_ops );
+ fprintf( stderr, "Request socket fd=%d thread=%p\n", sock->obj.fd, sock->thread );
+}
+
+/* handle a request socket event */
+static void request_socket_poll_event( struct object *obj, int event )
+{
+ struct request_socket *sock = (struct request_socket *)obj;
+ assert( obj->ops == &request_socket_ops );
+
+ if (event & (POLLERR | POLLHUP)) kill_thread( sock->thread, 0 );
+ else if (event & POLLIN)
+ {
+ struct thread *thread = sock->thread;
+ int ret;
+ char dummy[1];
+
+ ret = read( sock->obj.fd, &dummy, 1 );
+ if (ret > 0)
+ {
+ call_req_handler( thread );
+ return;
+ }
+ if (!ret) /* closed pipe */
+ {
+ kill_thread( thread, 0 );
+ return;
+ }
+ perror("read");
+ thread->exit_code = 1;
+ kill_thread( thread, 1 );
+ }
+}
+
+/* create a request socket and send the fd to the client thread */
+struct object *create_request_socket( struct thread *thread )
+{
+ struct request_socket *sock;
+ int fd[2];
+
+ if (pipe( fd )) return NULL;
+ if (!(sock = alloc_object( &request_socket_ops, fd[0] )))
+ {
+ close( fd[1] );
+ return NULL;
+ }
+ sock->thread = thread;
+ send_client_fd( thread, fd[1], -1 );
+ set_select_events( &sock->obj, POLLIN );
+ return &sock->obj;
+}
+
/* return the configuration directory ($WINEPREFIX or $HOME/.wine) */
const char *get_config_dir(void)
{