server: Moved the FSCTL_PIPE_LISTEN implementation to the server.
diff --git a/server/named_pipe.c b/server/named_pipe.c
index d4be777..9db5a58 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -69,6 +69,7 @@
{
struct object obj; /* object header */
struct fd *fd; /* pipe file descriptor */
+ struct fd *ioctl_fd; /* file descriptor for ioctls when not connected */
struct list entry; /* entry in named pipe servers list */
enum pipe_state state; /* server state */
struct pipe_client *client; /* client that this server is connected to */
@@ -297,28 +298,34 @@
return NULL;
}
-static struct fd *pipe_server_get_fd( struct object *obj )
+static void set_server_state( struct pipe_server *server, enum pipe_state state )
{
- struct pipe_server *server = (struct pipe_server *) obj;
+ server->state = state;
- switch(server->state)
+ switch(state)
{
case ps_connected_server:
case ps_wait_disconnect:
assert( server->fd );
- return (struct fd *) grab_object( server->fd );
-
+ break;
case ps_wait_open:
case ps_idle_server:
- set_error( STATUS_PIPE_LISTENING );
+ assert( !server->fd );
+ set_no_fd_status( server->ioctl_fd, STATUS_PIPE_LISTENING );
break;
-
case ps_disconnected_server:
case ps_wait_connect:
- set_error( STATUS_PIPE_DISCONNECTED );
+ assert( !server->fd );
+ set_no_fd_status( server->ioctl_fd, STATUS_PIPE_DISCONNECTED );
break;
}
- return NULL;
+}
+
+static struct fd *pipe_server_get_fd( struct object *obj )
+{
+ struct pipe_server *server = (struct pipe_server *) obj;
+
+ return (struct fd *)grab_object( server->fd ? server->fd : server->ioctl_fd );
}
@@ -383,6 +390,7 @@
assert( server->pipe->instances );
server->pipe->instances--;
+ if (server->ioctl_fd) release_object( server->ioctl_fd );
list_remove( &server->entry );
release_object( server->pipe );
}
@@ -403,12 +411,10 @@
case ps_connected_server:
/* Don't destroy the server's fd here as we can't
do a successful flush without it. */
- server->state = ps_wait_disconnect;
- release_object( client->fd );
- client->fd = NULL;
+ set_server_state( server, ps_wait_disconnect );
break;
case ps_disconnected_server:
- server->state = ps_wait_connect;
+ set_server_state( server, ps_wait_connect );
break;
case ps_idle_server:
case ps_wait_open:
@@ -420,7 +426,7 @@
server->client = NULL;
client->server = NULL;
}
- assert( !client->fd );
+ if (client->fd) release_object( client->fd );
}
static void named_pipe_device_dump( struct object *obj, int verbose )
@@ -567,13 +573,42 @@
return FD_TYPE_PIPE;
}
-static void pipe_server_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async,
+static void pipe_server_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data,
const void *data, data_size_t size )
{
struct pipe_server *server = get_fd_user( fd );
+ struct async *async;
switch(code)
{
+ case FSCTL_PIPE_LISTEN:
+ switch(server->state)
+ {
+ case ps_idle_server:
+ case ps_wait_connect:
+ set_server_state( server, ps_wait_open );
+ if ((async = create_async( current, server->wait_q, async_data )))
+ {
+ if (server->pipe->waiters) async_wake_up( server->pipe->waiters, STATUS_SUCCESS );
+ release_object( async );
+ set_error( STATUS_PENDING );
+ }
+ break;
+ case ps_connected_server:
+ set_error( STATUS_PIPE_CONNECTED );
+ break;
+ case ps_disconnected_server:
+ set_error( STATUS_PIPE_BUSY );
+ break;
+ case ps_wait_disconnect:
+ set_error( STATUS_NO_DATA_DETECTED );
+ break;
+ case ps_wait_open:
+ set_error( STATUS_INVALID_HANDLE );
+ break;
+ }
+ break;
+
case FSCTL_PIPE_DISCONNECT:
switch(server->state)
{
@@ -585,24 +620,27 @@
/* dump the client and server fds, but keep the pointers
around - client loses all waiting data */
- server->state = ps_disconnected_server;
do_disconnect( server );
+ set_server_state( server, ps_disconnected_server );
break;
case ps_wait_disconnect:
assert( !server->client );
do_disconnect( server );
- server->state = ps_wait_connect;
+ set_server_state( server, ps_wait_connect );
break;
case ps_idle_server:
case ps_wait_open:
+ set_error( STATUS_PIPE_LISTENING );
+ break;
case ps_disconnected_server:
case ps_wait_connect:
- assert(0); /* shouldn't even get an fd */
+ set_error( STATUS_PIPE_DISCONNECTED );
break;
}
break;
+
default:
- default_fd_ioctl( fd, code, async, data, size );
+ default_fd_ioctl( fd, code, async_data, data, size );
break;
}
}
@@ -668,7 +706,6 @@
server->fd = NULL;
server->pipe = pipe;
- server->state = ps_idle_server;
server->client = NULL;
server->flush_poll = NULL;
server->options = options;
@@ -676,7 +713,12 @@
list_add_head( &pipe->servers, &server->entry );
grab_object( pipe );
-
+ if (!(server->ioctl_fd = alloc_pseudo_fd( &pipe_server_fd_ops, &server->obj )))
+ {
+ release_object( server );
+ server = NULL;
+ }
+ set_server_state( server, ps_idle_server );
return server;
}
@@ -725,18 +767,13 @@
{
if (!socketpair( PF_UNIX, SOCK_STREAM, 0, fds ))
{
- int res = 0;
-
- assert( !client->fd );
assert( !server->fd );
/* for performance reasons, only set nonblocking mode when using
* overlapped I/O. Otherwise, we will be doing too much busy
* looping */
- if (is_overlapped( options ))
- res = fcntl( fds[1], F_SETFL, O_NONBLOCK );
- if ((res != -1) && is_overlapped( server->options ))
- res = fcntl( fds[0], F_SETFL, O_NONBLOCK );
+ if (is_overlapped( options )) fcntl( fds[1], F_SETFL, O_NONBLOCK );
+ if (is_overlapped( server->options )) fcntl( fds[0], F_SETFL, O_NONBLOCK );
if (pipe->insize)
{
@@ -751,17 +788,26 @@
client->fd = create_anonymous_fd( &pipe_client_fd_ops, fds[1], &client->obj, options );
server->fd = create_anonymous_fd( &pipe_server_fd_ops, fds[0], &server->obj, server->options );
- if (client->fd && server->fd && res != 1)
+ if (client->fd && server->fd)
{
if (server->state == ps_wait_open)
async_wake_up( server->wait_q, STATUS_SUCCESS );
- server->state = ps_connected_server;
+ set_server_state( server, ps_connected_server );
server->client = client;
client->server = server;
}
+ else
+ {
+ release_object( client );
+ client = NULL;
+ }
}
else
+ {
file_set_error();
+ release_object( client );
+ client = NULL;
+ }
}
release_object( server );
return &client->obj;
@@ -884,46 +930,6 @@
release_object( pipe );
}
-DECL_HANDLER(connect_named_pipe)
-{
- struct pipe_server *server;
- struct async *async;
-
- server = get_pipe_server_obj(current->process, req->handle, 0);
- if (!server)
- return;
-
- switch(server->state)
- {
- case ps_idle_server:
- case ps_wait_connect:
- assert( !server->fd );
- server->state = ps_wait_open;
- if ((async = create_async( current, server->wait_q, &req->async )))
- {
- if (server->pipe->waiters) async_wake_up( server->pipe->waiters, STATUS_SUCCESS );
- release_object( async );
- set_error( STATUS_PENDING );
- }
- break;
- case ps_connected_server:
- assert( server->fd );
- set_error( STATUS_PIPE_CONNECTED );
- break;
- case ps_disconnected_server:
- set_error( STATUS_PIPE_BUSY );
- break;
- case ps_wait_disconnect:
- set_error( STATUS_NO_DATA_DETECTED );
- break;
- case ps_wait_open:
- set_error( STATUS_INVALID_HANDLE );
- break;
- }
-
- release_object(server);
-}
-
DECL_HANDLER(get_named_pipe_info)
{
struct pipe_server *server;