blob: 95f06b9aab04ba51fae7a95c693bf1b6201bfa4d [file] [log] [blame]
Mike McCormackde7c3002001-07-10 19:16:49 +00001/*
2 * Server-side pipe management
3 *
4 * Copyright (C) 1998 Alexandre Julliard
Mike McCormackbf554572001-08-23 23:29:20 +00005 * Copyright (C) 2001 Mike McCormack
6 *
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00007 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
Jonathan Ernst360a3f92006-05-18 14:49:52 +020019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000020 *
Mike McCormackbf554572001-08-23 23:29:20 +000021 * TODO:
Mike McCormackef8b9462003-05-15 04:22:45 +000022 * message mode
Mike McCormackde7c3002001-07-10 19:16:49 +000023 */
24
25#include "config.h"
Alexandre Julliard5769d1d2002-04-26 19:05:15 +000026#include "wine/port.h"
Mike McCormackde7c3002001-07-10 19:16:49 +000027
28#include <assert.h>
29#include <fcntl.h>
30#include <string.h>
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000031#include <stdarg.h>
Mike McCormackde7c3002001-07-10 19:16:49 +000032#include <stdio.h>
33#include <stdlib.h>
34#include <sys/time.h>
35#include <sys/types.h>
Steven Edwards037c8a12003-02-11 22:27:13 +000036#ifdef HAVE_SYS_SOCKET_H
Mike McCormackde7c3002001-07-10 19:16:49 +000037#include <sys/socket.h>
Steven Edwards037c8a12003-02-11 22:27:13 +000038#endif
Mike McCormackde7c3002001-07-10 19:16:49 +000039#include <time.h>
40#include <unistd.h>
Steven Edwards57279182005-03-04 12:38:36 +000041#ifdef HAVE_POLL_H
42#include <poll.h>
43#endif
Mike McCormackde7c3002001-07-10 19:16:49 +000044
Ge van Geldorp1a1583a2005-11-28 17:32:54 +010045#include "ntstatus.h"
46#define WIN32_NO_STATUS
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000047#include "windef.h"
Robert Shearmane51dd362005-06-08 19:11:46 +000048#include "winternl.h"
Alexandre Julliard8c460952007-04-16 14:51:29 +020049#include "winioctl.h"
Mike McCormackde7c3002001-07-10 19:16:49 +000050
Alexandre Julliard863637b2003-01-30 00:26:44 +000051#include "file.h"
Mike McCormackde7c3002001-07-10 19:16:49 +000052#include "handle.h"
53#include "thread.h"
54#include "request.h"
55
Mike McCormackbf554572001-08-23 23:29:20 +000056enum pipe_state
57{
Mike McCormackbf554572001-08-23 23:29:20 +000058 ps_idle_server,
59 ps_wait_open,
Mike McCormackbf554572001-08-23 23:29:20 +000060 ps_connected_server,
Mike McCormackef8b9462003-05-15 04:22:45 +000061 ps_wait_disconnect,
62 ps_disconnected_server,
63 ps_wait_connect
64};
65
Mike McCormackde7c3002001-07-10 19:16:49 +000066struct named_pipe;
67
Mike McCormackef8b9462003-05-15 04:22:45 +000068struct pipe_server
Mike McCormackde7c3002001-07-10 19:16:49 +000069{
Alexandre Julliard7c1cf8f2005-02-03 10:48:23 +000070 struct object obj; /* object header */
71 struct fd *fd; /* pipe file descriptor */
Alexandre Julliard6105a932007-04-18 16:26:37 +020072 struct fd *ioctl_fd; /* file descriptor for ioctls when not connected */
Alexandre Julliard7c1cf8f2005-02-03 10:48:23 +000073 struct list entry; /* entry in named pipe servers list */
74 enum pipe_state state; /* server state */
75 struct pipe_client *client; /* client that this server is connected to */
Mike McCormackef8b9462003-05-15 04:22:45 +000076 struct named_pipe *pipe;
Mike McCormackef8b9462003-05-15 04:22:45 +000077 struct timeout_user *flush_poll;
78 struct event *event;
Robert Shearmane51dd362005-06-08 19:11:46 +000079 unsigned int options; /* pipe options */
Mike McCormackef8b9462003-05-15 04:22:45 +000080};
81
82struct pipe_client
83{
Alexandre Julliard7c1cf8f2005-02-03 10:48:23 +000084 struct object obj; /* object header */
85 struct fd *fd; /* pipe file descriptor */
86 struct pipe_server *server; /* server that this client is connected to */
Robert Shearmane51dd362005-06-08 19:11:46 +000087 unsigned int flags; /* file flags */
Mike McCormackde7c3002001-07-10 19:16:49 +000088};
89
90struct named_pipe
91{
92 struct object obj; /* object header */
Eric Pouech5a2591d2005-04-18 14:57:04 +000093 unsigned int flags;
Mike McCormackde7c3002001-07-10 19:16:49 +000094 unsigned int maxinstances;
95 unsigned int outsize;
96 unsigned int insize;
Mike McCormackef8b9462003-05-15 04:22:45 +000097 unsigned int instances;
Alexandre Julliardaaf477f2007-04-17 20:08:59 +020098 timeout_t timeout;
Alexandre Julliard7c1cf8f2005-02-03 10:48:23 +000099 struct list servers; /* list of servers using this pipe */
Alexandre Julliarddf09ac52007-04-02 20:09:29 +0200100 struct async_queue *waiters; /* list of clients waiting to connect */
Mike McCormackde7c3002001-07-10 19:16:49 +0000101};
102
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100103struct named_pipe_device
104{
105 struct object obj; /* object header */
Alexandre Julliard26e60d82005-12-12 14:30:06 +0100106 struct fd *fd; /* pseudo-fd for ioctls */
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100107 struct namespace *pipes; /* named pipe namespace */
108};
109
Mike McCormackde7c3002001-07-10 19:16:49 +0000110static void named_pipe_dump( struct object *obj, int verbose );
Alexandre Julliarda510a7e2005-12-12 16:46:17 +0100111static unsigned int named_pipe_map_access( struct object *obj, unsigned int access );
Alexandre Julliardde1866d2007-03-22 16:47:46 +0100112static struct object *named_pipe_open_file( struct object *obj, unsigned int access,
113 unsigned int sharing, unsigned int options );
Mike McCormackef8b9462003-05-15 04:22:45 +0000114static void named_pipe_destroy( struct object *obj );
Mike McCormackde7c3002001-07-10 19:16:49 +0000115
116static const struct object_ops named_pipe_ops =
117{
118 sizeof(struct named_pipe), /* size */
119 named_pipe_dump, /* dump */
Alexandre Julliard8382eb02007-12-05 18:16:42 +0100120 no_get_type, /* get_type */
Mike McCormackde7c3002001-07-10 19:16:49 +0000121 no_add_queue, /* add_queue */
122 NULL, /* remove_queue */
123 NULL, /* signaled */
124 NULL, /* satisfied */
Mike McCormackf92fff62005-04-24 17:35:52 +0000125 no_signal, /* signal */
Mike McCormackde7c3002001-07-10 19:16:49 +0000126 no_get_fd, /* get_fd */
Alexandre Julliarda510a7e2005-12-12 16:46:17 +0100127 named_pipe_map_access, /* map_access */
Rob Shearmanc1707d82007-10-03 13:10:37 +0100128 default_get_sd, /* get_sd */
129 default_set_sd, /* set_sd */
Vitaliy Margolenbaffcb92005-11-22 14:55:42 +0000130 no_lookup_name, /* lookup_name */
Alexandre Julliardde1866d2007-03-22 16:47:46 +0100131 named_pipe_open_file, /* open_file */
Alexandre Julliardb9b1ea92005-06-09 15:39:52 +0000132 no_close_handle, /* close_handle */
Mike McCormackde7c3002001-07-10 19:16:49 +0000133 named_pipe_destroy /* destroy */
134};
135
Mike McCormackef8b9462003-05-15 04:22:45 +0000136/* server end functions */
137static void pipe_server_dump( struct object *obj, int verbose );
138static struct fd *pipe_server_get_fd( struct object *obj );
139static void pipe_server_destroy( struct object *obj);
Alexandre Julliarddf651872007-03-27 16:51:44 +0200140static void pipe_server_flush( struct fd *fd, struct event **event );
Alexandre Julliard7a9363a2007-04-10 22:26:23 +0200141static enum server_fd_type pipe_server_get_fd_type( struct fd *fd );
Alexandre Julliardfd59e152007-05-03 17:43:18 +0200142static obj_handle_t pipe_server_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async,
Alexandre Julliard7ec95c52008-12-30 20:37:20 +0100143 int blocking, const void *data, data_size_t size );
Mike McCormackde7c3002001-07-10 19:16:49 +0000144
Mike McCormackef8b9462003-05-15 04:22:45 +0000145static const struct object_ops pipe_server_ops =
Mike McCormackde7c3002001-07-10 19:16:49 +0000146{
Mike McCormackef8b9462003-05-15 04:22:45 +0000147 sizeof(struct pipe_server), /* size */
148 pipe_server_dump, /* dump */
Alexandre Julliard8382eb02007-12-05 18:16:42 +0100149 no_get_type, /* get_type */
Alexandre Julliardba896e72007-04-04 19:39:29 +0200150 add_queue, /* add_queue */
151 remove_queue, /* remove_queue */
Alexandre Julliard863637b2003-01-30 00:26:44 +0000152 default_fd_signaled, /* signaled */
Mike McCormackde7c3002001-07-10 19:16:49 +0000153 no_satisfied, /* satisfied */
Mike McCormackf92fff62005-04-24 17:35:52 +0000154 no_signal, /* signal */
Mike McCormackef8b9462003-05-15 04:22:45 +0000155 pipe_server_get_fd, /* get_fd */
Alexandre Julliard24001e82007-10-02 14:20:15 +0200156 default_fd_map_access, /* map_access */
Rob Shearmanc1707d82007-10-03 13:10:37 +0100157 default_get_sd, /* get_sd */
158 default_set_sd, /* set_sd */
Vitaliy Margolenbaffcb92005-11-22 14:55:42 +0000159 no_lookup_name, /* lookup_name */
Alexandre Julliard7e71c1d2007-03-22 11:44:29 +0100160 no_open_file, /* open_file */
Alexandre Julliard715d78e2006-11-02 20:52:22 +0100161 fd_close_handle, /* close_handle */
Mike McCormackef8b9462003-05-15 04:22:45 +0000162 pipe_server_destroy /* destroy */
Alexandre Julliard863637b2003-01-30 00:26:44 +0000163};
164
Mike McCormackef8b9462003-05-15 04:22:45 +0000165static const struct fd_ops pipe_server_fd_ops =
Alexandre Julliard863637b2003-01-30 00:26:44 +0000166{
Alexandre Julliard72bff2e2007-04-10 17:07:27 +0200167 default_fd_get_poll_events, /* get_poll_events */
Mike McCormackde7c3002001-07-10 19:16:49 +0000168 default_poll_event, /* poll_event */
Mike McCormackef8b9462003-05-15 04:22:45 +0000169 pipe_server_flush, /* flush */
Alexandre Julliard7a9363a2007-04-10 22:26:23 +0200170 pipe_server_get_fd_type, /* get_fd_type */
Alexandre Julliard8c460952007-04-16 14:51:29 +0200171 pipe_server_ioctl, /* ioctl */
Robert Shearmane51dd362005-06-08 19:11:46 +0000172 default_fd_queue_async, /* queue_async */
Alexandre Julliard72bff2e2007-04-10 17:07:27 +0200173 default_fd_reselect_async, /* reselect_async */
Robert Shearmane51dd362005-06-08 19:11:46 +0000174 default_fd_cancel_async, /* cancel_async */
Mike McCormackef8b9462003-05-15 04:22:45 +0000175};
176
177/* client end functions */
178static void pipe_client_dump( struct object *obj, int verbose );
Alexandre Julliard7a344c12009-06-09 12:11:05 +0200179static int pipe_client_signaled( struct object *obj, struct thread *thread );
Mike McCormackef8b9462003-05-15 04:22:45 +0000180static struct fd *pipe_client_get_fd( struct object *obj );
181static void pipe_client_destroy( struct object *obj );
Alexandre Julliarddf651872007-03-27 16:51:44 +0200182static void pipe_client_flush( struct fd *fd, struct event **event );
Alexandre Julliard7a9363a2007-04-10 22:26:23 +0200183static enum server_fd_type pipe_client_get_fd_type( struct fd *fd );
Mike McCormackef8b9462003-05-15 04:22:45 +0000184
185static const struct object_ops pipe_client_ops =
186{
187 sizeof(struct pipe_client), /* size */
188 pipe_client_dump, /* dump */
Alexandre Julliard8382eb02007-12-05 18:16:42 +0100189 no_get_type, /* get_type */
Alexandre Julliardba896e72007-04-04 19:39:29 +0200190 add_queue, /* add_queue */
191 remove_queue, /* remove_queue */
Alexandre Julliard7a344c12009-06-09 12:11:05 +0200192 pipe_client_signaled, /* signaled */
Mike McCormackef8b9462003-05-15 04:22:45 +0000193 no_satisfied, /* satisfied */
Mike McCormackf92fff62005-04-24 17:35:52 +0000194 no_signal, /* signal */
Mike McCormackef8b9462003-05-15 04:22:45 +0000195 pipe_client_get_fd, /* get_fd */
Alexandre Julliard24001e82007-10-02 14:20:15 +0200196 default_fd_map_access, /* map_access */
Rob Shearmanc1707d82007-10-03 13:10:37 +0100197 default_get_sd, /* get_sd */
198 default_set_sd, /* set_sd */
Vitaliy Margolenbaffcb92005-11-22 14:55:42 +0000199 no_lookup_name, /* lookup_name */
Alexandre Julliard7e71c1d2007-03-22 11:44:29 +0100200 no_open_file, /* open_file */
Alexandre Julliard715d78e2006-11-02 20:52:22 +0100201 fd_close_handle, /* close_handle */
Mike McCormackef8b9462003-05-15 04:22:45 +0000202 pipe_client_destroy /* destroy */
203};
204
205static const struct fd_ops pipe_client_fd_ops =
206{
Robert Shearmane51dd362005-06-08 19:11:46 +0000207 default_fd_get_poll_events, /* get_poll_events */
Mike McCormackef8b9462003-05-15 04:22:45 +0000208 default_poll_event, /* poll_event */
209 pipe_client_flush, /* flush */
Alexandre Julliard7a9363a2007-04-10 22:26:23 +0200210 pipe_client_get_fd_type, /* get_fd_type */
Alexandre Julliard63571432007-04-16 14:45:03 +0200211 default_fd_ioctl, /* ioctl */
Robert Shearmane51dd362005-06-08 19:11:46 +0000212 default_fd_queue_async, /* queue_async */
Alexandre Julliard72bff2e2007-04-10 17:07:27 +0200213 default_fd_reselect_async, /* reselect_async */
Robert Shearmane51dd362005-06-08 19:11:46 +0000214 default_fd_cancel_async /* cancel_async */
Mike McCormackde7c3002001-07-10 19:16:49 +0000215};
216
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100217static void named_pipe_device_dump( struct object *obj, int verbose );
Alexandre Julliard8382eb02007-12-05 18:16:42 +0100218static struct object_type *named_pipe_device_get_type( struct object *obj );
Alexandre Julliard26e60d82005-12-12 14:30:06 +0100219static struct fd *named_pipe_device_get_fd( struct object *obj );
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100220static struct object *named_pipe_device_lookup_name( struct object *obj,
221 struct unicode_str *name, unsigned int attr );
Alexandre Julliard94655c82007-03-22 11:52:40 +0100222static struct object *named_pipe_device_open_file( struct object *obj, unsigned int access,
223 unsigned int sharing, unsigned int options );
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100224static void named_pipe_device_destroy( struct object *obj );
Alexandre Julliard7a9363a2007-04-10 22:26:23 +0200225static enum server_fd_type named_pipe_device_get_fd_type( struct fd *fd );
Alexandre Julliardfd59e152007-05-03 17:43:18 +0200226static obj_handle_t named_pipe_device_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data,
Alexandre Julliard7ec95c52008-12-30 20:37:20 +0100227 int blocking, const void *data, data_size_t size );
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100228
229static const struct object_ops named_pipe_device_ops =
230{
231 sizeof(struct named_pipe_device), /* size */
232 named_pipe_device_dump, /* dump */
Alexandre Julliard8382eb02007-12-05 18:16:42 +0100233 named_pipe_device_get_type, /* get_type */
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100234 no_add_queue, /* add_queue */
235 NULL, /* remove_queue */
236 NULL, /* signaled */
237 no_satisfied, /* satisfied */
238 no_signal, /* signal */
Alexandre Julliard26e60d82005-12-12 14:30:06 +0100239 named_pipe_device_get_fd, /* get_fd */
Alexandre Julliardbf5b6c92007-04-18 16:32:31 +0200240 no_map_access, /* map_access */
Rob Shearmanc1707d82007-10-03 13:10:37 +0100241 default_get_sd, /* get_sd */
242 default_set_sd, /* set_sd */
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100243 named_pipe_device_lookup_name, /* lookup_name */
Alexandre Julliard94655c82007-03-22 11:52:40 +0100244 named_pipe_device_open_file, /* open_file */
Alexandre Julliard715d78e2006-11-02 20:52:22 +0100245 fd_close_handle, /* close_handle */
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100246 named_pipe_device_destroy /* destroy */
247};
248
Alexandre Julliard26e60d82005-12-12 14:30:06 +0100249static const struct fd_ops named_pipe_device_fd_ops =
250{
Alexandre Julliard1acb9302005-12-13 12:00:11 +0100251 default_fd_get_poll_events, /* get_poll_events */
252 default_poll_event, /* poll_event */
253 no_flush, /* flush */
Alexandre Julliard7a9363a2007-04-10 22:26:23 +0200254 named_pipe_device_get_fd_type, /* get_fd_type */
Alexandre Julliard3684dc12007-04-17 22:07:07 +0200255 named_pipe_device_ioctl, /* ioctl */
Alexandre Julliard1acb9302005-12-13 12:00:11 +0100256 default_fd_queue_async, /* queue_async */
Alexandre Julliard72bff2e2007-04-10 17:07:27 +0200257 default_fd_reselect_async, /* reselect_async */
Alexandre Julliard1acb9302005-12-13 12:00:11 +0100258 default_fd_cancel_async /* cancel_async */
Alexandre Julliard26e60d82005-12-12 14:30:06 +0100259};
260
Mike McCormackde7c3002001-07-10 19:16:49 +0000261static void named_pipe_dump( struct object *obj, int verbose )
262{
Mike McCormackef8b9462003-05-15 04:22:45 +0000263 struct named_pipe *pipe = (struct named_pipe *) obj;
Mike McCormackde7c3002001-07-10 19:16:49 +0000264 assert( obj->ops == &named_pipe_ops );
Alexandre Julliard7c1cf8f2005-02-03 10:48:23 +0000265 fprintf( stderr, "Named pipe " );
266 dump_object_name( &pipe->obj );
267 fprintf( stderr, "\n" );
Mike McCormackde7c3002001-07-10 19:16:49 +0000268}
269
Alexandre Julliarda510a7e2005-12-12 16:46:17 +0100270static unsigned int named_pipe_map_access( struct object *obj, unsigned int access )
271{
272 if (access & GENERIC_READ) access |= STANDARD_RIGHTS_READ;
273 if (access & GENERIC_WRITE) access |= STANDARD_RIGHTS_WRITE | FILE_CREATE_PIPE_INSTANCE;
274 if (access & GENERIC_EXECUTE) access |= STANDARD_RIGHTS_EXECUTE;
275 if (access & GENERIC_ALL) access |= STANDARD_RIGHTS_ALL;
276 return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL);
277}
278
Mike McCormackef8b9462003-05-15 04:22:45 +0000279static void pipe_server_dump( struct object *obj, int verbose )
Mike McCormackde7c3002001-07-10 19:16:49 +0000280{
Mike McCormackef8b9462003-05-15 04:22:45 +0000281 struct pipe_server *server = (struct pipe_server *) obj;
282 assert( obj->ops == &pipe_server_ops );
Alexandre Julliard7c1cf8f2005-02-03 10:48:23 +0000283 fprintf( stderr, "Named pipe server pipe=%p state=%d\n", server->pipe, server->state );
Mike McCormackef8b9462003-05-15 04:22:45 +0000284}
285
286static void pipe_client_dump( struct object *obj, int verbose )
287{
288 struct pipe_client *client = (struct pipe_client *) obj;
Alexandre Julliard7c1cf8f2005-02-03 10:48:23 +0000289 assert( obj->ops == &pipe_client_ops );
290 fprintf( stderr, "Named pipe client server=%p\n", client->server );
Mike McCormackde7c3002001-07-10 19:16:49 +0000291}
292
Alexandre Julliard7a344c12009-06-09 12:11:05 +0200293static int pipe_client_signaled( struct object *obj, struct thread *thread )
294{
295 struct pipe_client *client = (struct pipe_client *) obj;
296
297 return client->fd && is_fd_signaled(client->fd);
298}
299
Alexandre Julliard7c1cf8f2005-02-03 10:48:23 +0000300static void named_pipe_destroy( struct object *obj)
301{
302 struct named_pipe *pipe = (struct named_pipe *) obj;
303
304 assert( list_empty( &pipe->servers ) );
305 assert( !pipe->instances );
Alexandre Julliardb2cba952007-04-03 19:36:07 +0200306 free_async_queue( pipe->waiters );
Mike McCormackef8b9462003-05-15 04:22:45 +0000307}
308
309static struct fd *pipe_client_get_fd( struct object *obj )
310{
311 struct pipe_client *client = (struct pipe_client *) obj;
Robert Shearman37957092005-06-10 19:54:46 +0000312 if (client->fd)
Mike McCormackef8b9462003-05-15 04:22:45 +0000313 return (struct fd *) grab_object( client->fd );
Bill Medland3f7c3ff2003-04-17 02:14:04 +0000314 set_error( STATUS_PIPE_DISCONNECTED );
315 return NULL;
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000316}
317
Alexandre Julliard6105a932007-04-18 16:26:37 +0200318static void set_server_state( struct pipe_server *server, enum pipe_state state )
Mike McCormackde7c3002001-07-10 19:16:49 +0000319{
Alexandre Julliard6105a932007-04-18 16:26:37 +0200320 server->state = state;
Mike McCormackde7c3002001-07-10 19:16:49 +0000321
Alexandre Julliard6105a932007-04-18 16:26:37 +0200322 switch(state)
Mike McCormackbf554572001-08-23 23:29:20 +0000323 {
Mike McCormackef8b9462003-05-15 04:22:45 +0000324 case ps_connected_server:
325 case ps_wait_disconnect:
326 assert( server->fd );
Alexandre Julliard6105a932007-04-18 16:26:37 +0200327 break;
Mike McCormackef8b9462003-05-15 04:22:45 +0000328 case ps_wait_open:
329 case ps_idle_server:
Alexandre Julliard6105a932007-04-18 16:26:37 +0200330 assert( !server->fd );
331 set_no_fd_status( server->ioctl_fd, STATUS_PIPE_LISTENING );
Mike McCormackef8b9462003-05-15 04:22:45 +0000332 break;
Mike McCormackef8b9462003-05-15 04:22:45 +0000333 case ps_disconnected_server:
334 case ps_wait_connect:
Alexandre Julliard6105a932007-04-18 16:26:37 +0200335 assert( !server->fd );
336 set_no_fd_status( server->ioctl_fd, STATUS_PIPE_DISCONNECTED );
Mike McCormackef8b9462003-05-15 04:22:45 +0000337 break;
Mike McCormackef8b9462003-05-15 04:22:45 +0000338 }
Alexandre Julliard6105a932007-04-18 16:26:37 +0200339}
340
341static struct fd *pipe_server_get_fd( struct object *obj )
342{
343 struct pipe_server *server = (struct pipe_server *) obj;
344
345 return (struct fd *)grab_object( server->fd ? server->fd : server->ioctl_fd );
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000346}
347
Mike McCormackef8b9462003-05-15 04:22:45 +0000348
349static void notify_empty( struct pipe_server *server )
350{
Robert Shearman37957092005-06-10 19:54:46 +0000351 if (!server->flush_poll)
Mike McCormackef8b9462003-05-15 04:22:45 +0000352 return;
353 assert( server->state == ps_connected_server );
354 assert( server->event );
355 remove_timeout_user( server->flush_poll );
356 server->flush_poll = NULL;
357 set_event( server->event );
358 release_object( server->event );
359 server->event = NULL;
360}
361
362static void do_disconnect( struct pipe_server *server )
363{
364 /* we may only have a server fd, if the client disconnected */
Robert Shearman37957092005-06-10 19:54:46 +0000365 if (server->client)
Mike McCormackef8b9462003-05-15 04:22:45 +0000366 {
367 assert( server->client->server == server );
368 assert( server->client->fd );
369 release_object( server->client->fd );
370 server->client->fd = NULL;
371 }
372 assert( server->fd );
Alexandre Julliardbc426ab2007-04-10 21:30:37 +0200373 shutdown( get_unix_fd( server->fd ), SHUT_RDWR );
Mike McCormackef8b9462003-05-15 04:22:45 +0000374 release_object( server->fd );
375 server->fd = NULL;
376}
377
378static void pipe_server_destroy( struct object *obj)
379{
380 struct pipe_server *server = (struct pipe_server *)obj;
381
382 assert( obj->ops == &pipe_server_ops );
383
Robert Shearman37957092005-06-10 19:54:46 +0000384 if (server->fd)
Mike McCormackef8b9462003-05-15 04:22:45 +0000385 {
386 notify_empty( server );
387 do_disconnect( server );
388 }
389
Robert Shearman37957092005-06-10 19:54:46 +0000390 if (server->client)
Mike McCormackef8b9462003-05-15 04:22:45 +0000391 {
392 server->client->server = NULL;
393 server->client = NULL;
394 }
395
Mike McCormackef8b9462003-05-15 04:22:45 +0000396 assert( server->pipe->instances );
397 server->pipe->instances--;
398
Alexandre Julliard6105a932007-04-18 16:26:37 +0200399 if (server->ioctl_fd) release_object( server->ioctl_fd );
Alexandre Julliard7c1cf8f2005-02-03 10:48:23 +0000400 list_remove( &server->entry );
Mike McCormackef8b9462003-05-15 04:22:45 +0000401 release_object( server->pipe );
402}
403
404static void pipe_client_destroy( struct object *obj)
405{
406 struct pipe_client *client = (struct pipe_client *)obj;
407 struct pipe_server *server = client->server;
408
409 assert( obj->ops == &pipe_client_ops );
410
Robert Shearman37957092005-06-10 19:54:46 +0000411 if (server)
Mike McCormackef8b9462003-05-15 04:22:45 +0000412 {
413 notify_empty( server );
414
Robert Shearman37957092005-06-10 19:54:46 +0000415 switch(server->state)
Mike McCormackef8b9462003-05-15 04:22:45 +0000416 {
417 case ps_connected_server:
418 /* Don't destroy the server's fd here as we can't
419 do a successful flush without it. */
Alexandre Julliard6105a932007-04-18 16:26:37 +0200420 set_server_state( server, ps_wait_disconnect );
Mike McCormackef8b9462003-05-15 04:22:45 +0000421 break;
422 case ps_disconnected_server:
Alexandre Julliard6105a932007-04-18 16:26:37 +0200423 set_server_state( server, ps_wait_connect );
Mike McCormackef8b9462003-05-15 04:22:45 +0000424 break;
Alexandre Julliard7c1cf8f2005-02-03 10:48:23 +0000425 case ps_idle_server:
426 case ps_wait_open:
427 case ps_wait_disconnect:
428 case ps_wait_connect:
Mike McCormackef8b9462003-05-15 04:22:45 +0000429 assert( 0 );
430 }
431 assert( server->client );
432 server->client = NULL;
433 client->server = NULL;
434 }
Alexandre Julliard6105a932007-04-18 16:26:37 +0200435 if (client->fd) release_object( client->fd );
Mike McCormackef8b9462003-05-15 04:22:45 +0000436}
437
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100438static void named_pipe_device_dump( struct object *obj, int verbose )
439{
440 assert( obj->ops == &named_pipe_device_ops );
441 fprintf( stderr, "Named pipe device\n" );
442}
443
Alexandre Julliard8382eb02007-12-05 18:16:42 +0100444static struct object_type *named_pipe_device_get_type( struct object *obj )
445{
446 static const WCHAR name[] = {'D','e','v','i','c','e'};
447 static const struct unicode_str str = { name, sizeof(name) };
448 return get_object_type( &str );
449}
450
Alexandre Julliard26e60d82005-12-12 14:30:06 +0100451static struct fd *named_pipe_device_get_fd( struct object *obj )
452{
453 struct named_pipe_device *device = (struct named_pipe_device *)obj;
Alexandre Julliard5bcd0882005-12-13 11:22:28 +0100454 return (struct fd *)grab_object( device->fd );
Alexandre Julliard26e60d82005-12-12 14:30:06 +0100455}
456
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100457static struct object *named_pipe_device_lookup_name( struct object *obj, struct unicode_str *name,
458 unsigned int attr )
459{
460 struct named_pipe_device *device = (struct named_pipe_device*)obj;
461 struct object *found;
462
463 assert( obj->ops == &named_pipe_device_ops );
464 assert( device->pipes );
465
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100466 if ((found = find_object( device->pipes, name, attr | OBJ_CASE_INSENSITIVE )))
467 name->len = 0;
468
469 return found;
470}
471
Alexandre Julliard94655c82007-03-22 11:52:40 +0100472static struct object *named_pipe_device_open_file( struct object *obj, unsigned int access,
473 unsigned int sharing, unsigned int options )
474{
475 return grab_object( obj );
476}
477
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100478static void named_pipe_device_destroy( struct object *obj )
479{
480 struct named_pipe_device *device = (struct named_pipe_device*)obj;
481 assert( obj->ops == &named_pipe_device_ops );
Alexandre Julliard26e60d82005-12-12 14:30:06 +0100482 if (device->fd) release_object( device->fd );
Michael Stefaniuc5ceccec2006-10-09 23:34:36 +0200483 free( device->pipes );
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100484}
485
Alexandre Julliard7a9363a2007-04-10 22:26:23 +0200486static enum server_fd_type named_pipe_device_get_fd_type( struct fd *fd )
Alexandre Julliard1acb9302005-12-13 12:00:11 +0100487{
Alexandre Julliard89304272006-11-20 14:14:04 +0100488 return FD_TYPE_DEVICE;
Alexandre Julliard1acb9302005-12-13 12:00:11 +0100489}
490
Alexandre Julliardb00fb172006-03-22 20:32:04 +0100491void create_named_pipe_device( struct directory *root, const struct unicode_str *name )
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100492{
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100493 struct named_pipe_device *dev;
494
Alexandre Julliardd13095b2005-12-05 14:52:02 +0100495 if ((dev = create_named_object_dir( root, name, 0, &named_pipe_device_ops )) &&
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100496 get_error() != STATUS_OBJECT_NAME_EXISTS)
497 {
Alexandre Julliard26e60d82005-12-12 14:30:06 +0100498 dev->pipes = NULL;
Alexandre Julliard017480d2007-05-03 16:07:30 +0200499 if (!(dev->fd = alloc_pseudo_fd( &named_pipe_device_fd_ops, &dev->obj, 0 )) ||
Alexandre Julliard26e60d82005-12-12 14:30:06 +0100500 !(dev->pipes = create_namespace( 7 )))
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100501 {
502 release_object( dev );
503 dev = NULL;
504 }
505 }
Alexandre Julliardb00fb172006-03-22 20:32:04 +0100506 if (dev) make_object_static( &dev->obj );
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100507}
508
Mike McCormackef8b9462003-05-15 04:22:45 +0000509static int pipe_data_remaining( struct pipe_server *server )
510{
511 struct pollfd pfd;
512 int fd;
513
514 assert( server->client );
515
516 fd = get_unix_fd( server->client->fd );
Robert Shearman37957092005-06-10 19:54:46 +0000517 if (fd < 0)
Mike McCormackef8b9462003-05-15 04:22:45 +0000518 return 0;
519 pfd.fd = fd;
520 pfd.events = POLLIN;
521 pfd.revents = 0;
522
Robert Shearman37957092005-06-10 19:54:46 +0000523 if (0 > poll( &pfd, 1, 0 ))
Mike McCormackef8b9462003-05-15 04:22:45 +0000524 return 0;
525
526 return pfd.revents&POLLIN;
527}
528
529static void check_flushed( void *arg )
530{
531 struct pipe_server *server = (struct pipe_server*) arg;
532
533 assert( server->event );
Robert Shearman37957092005-06-10 19:54:46 +0000534 if (pipe_data_remaining( server ))
Mike McCormackef8b9462003-05-15 04:22:45 +0000535 {
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200536 server->flush_poll = add_timeout_user( -TICKS_PER_SEC / 10, check_flushed, server );
Mike McCormackef8b9462003-05-15 04:22:45 +0000537 }
538 else
Mike McCormack99a6efa2004-07-15 18:59:58 +0000539 {
540 /* notify_empty( server ); */
541 server->flush_poll = NULL;
542 set_event( server->event );
543 release_object( server->event );
544 server->event = NULL;
545 }
Mike McCormackef8b9462003-05-15 04:22:45 +0000546}
547
Alexandre Julliarddf651872007-03-27 16:51:44 +0200548static void pipe_server_flush( struct fd *fd, struct event **event )
Mike McCormackef8b9462003-05-15 04:22:45 +0000549{
550 struct pipe_server *server = get_fd_user( fd );
551
Alexandre Julliarddf651872007-03-27 16:51:44 +0200552 if (!server || server->state != ps_connected_server) return;
Mike McCormackef8b9462003-05-15 04:22:45 +0000553
554 /* FIXME: if multiple threads flush the same pipe,
555 maybe should create a list of processes to notify */
Alexandre Julliarddf651872007-03-27 16:51:44 +0200556 if (server->flush_poll) return;
Mike McCormackef8b9462003-05-15 04:22:45 +0000557
Robert Shearman37957092005-06-10 19:54:46 +0000558 if (pipe_data_remaining( server ))
Mike McCormackef8b9462003-05-15 04:22:45 +0000559 {
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200560 /* this kind of sux -
Mike McCormackef8b9462003-05-15 04:22:45 +0000561 there's no unix way to be alerted when a pipe becomes empty */
Rob Shearmandd9e3922007-10-24 16:04:42 +0100562 server->event = create_event( NULL, NULL, 0, 0, 0, NULL );
Alexandre Julliarddf651872007-03-27 16:51:44 +0200563 if (!server->event) return;
Alexandre Julliardaaf477f2007-04-17 20:08:59 +0200564 server->flush_poll = add_timeout_user( -TICKS_PER_SEC / 10, check_flushed, server );
Mike McCormackef8b9462003-05-15 04:22:45 +0000565 *event = server->event;
566 }
Mike McCormackef8b9462003-05-15 04:22:45 +0000567}
568
Alexandre Julliarddf651872007-03-27 16:51:44 +0200569static void pipe_client_flush( struct fd *fd, struct event **event )
Mike McCormackef8b9462003-05-15 04:22:45 +0000570{
571 /* FIXME: what do we have to do for this? */
Mike McCormackef8b9462003-05-15 04:22:45 +0000572}
573
Robert Shearmane51dd362005-06-08 19:11:46 +0000574static inline int is_overlapped( unsigned int options )
Alexandre Julliard646d6212001-10-05 19:45:45 +0000575{
Robert Shearmane51dd362005-06-08 19:11:46 +0000576 return !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT));
577}
578
Alexandre Julliard7a9363a2007-04-10 22:26:23 +0200579static enum server_fd_type pipe_server_get_fd_type( struct fd *fd )
Robert Shearmane51dd362005-06-08 19:11:46 +0000580{
Alexandre Julliard89304272006-11-20 14:14:04 +0100581 return FD_TYPE_PIPE;
Robert Shearmane51dd362005-06-08 19:11:46 +0000582}
583
Alexandre Julliard7a9363a2007-04-10 22:26:23 +0200584static enum server_fd_type pipe_client_get_fd_type( struct fd *fd )
Robert Shearmane51dd362005-06-08 19:11:46 +0000585{
Alexandre Julliard89304272006-11-20 14:14:04 +0100586 return FD_TYPE_PIPE;
Alexandre Julliard646d6212001-10-05 19:45:45 +0000587}
588
Alexandre Julliard63a23722007-05-03 17:44:05 +0200589static obj_handle_t alloc_wait_event( struct process *process )
590{
591 obj_handle_t handle = 0;
Rob Shearmandd9e3922007-10-24 16:04:42 +0100592 struct event *event = create_event( NULL, NULL, 0, 1, 0, NULL );
Alexandre Julliard63a23722007-05-03 17:44:05 +0200593
594 if (event)
595 {
596 handle = alloc_handle( process, event, EVENT_ALL_ACCESS, 0 );
597 release_object( event );
598 }
599 return handle;
600}
601
Alexandre Julliardfd59e152007-05-03 17:43:18 +0200602static obj_handle_t pipe_server_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data,
Alexandre Julliard7ec95c52008-12-30 20:37:20 +0100603 int blocking, const void *data, data_size_t size )
Alexandre Julliard8c460952007-04-16 14:51:29 +0200604{
605 struct pipe_server *server = get_fd_user( fd );
Alexandre Julliard6105a932007-04-18 16:26:37 +0200606 struct async *async;
Alexandre Julliard63a23722007-05-03 17:44:05 +0200607 obj_handle_t wait_handle = 0;
Alexandre Julliard8c460952007-04-16 14:51:29 +0200608
609 switch(code)
610 {
Alexandre Julliard6105a932007-04-18 16:26:37 +0200611 case FSCTL_PIPE_LISTEN:
612 switch(server->state)
613 {
614 case ps_idle_server:
615 case ps_wait_connect:
Andrey Turkin85cc2c12010-05-22 22:00:59 +0400616 if (blocking)
Alexandre Julliard6105a932007-04-18 16:26:37 +0200617 {
Alexandre Julliard63a23722007-05-03 17:44:05 +0200618 async_data_t new_data = *async_data;
619 if (!(wait_handle = alloc_wait_event( current->process ))) break;
620 new_data.event = wait_handle;
Alexandre Julliard9ed42d22008-12-26 12:27:48 +0100621 if (!(async = fd_queue_async( server->ioctl_fd, &new_data, ASYNC_TYPE_WAIT )))
Alexandre Julliard63a23722007-05-03 17:44:05 +0200622 {
623 close_handle( current->process, wait_handle );
624 break;
625 }
626 }
Alexandre Julliard9ed42d22008-12-26 12:27:48 +0100627 else async = fd_queue_async( server->ioctl_fd, async_data, ASYNC_TYPE_WAIT );
Alexandre Julliard63a23722007-05-03 17:44:05 +0200628
629 if (async)
630 {
631 set_server_state( server, ps_wait_open );
Alexandre Julliard6105a932007-04-18 16:26:37 +0200632 if (server->pipe->waiters) async_wake_up( server->pipe->waiters, STATUS_SUCCESS );
633 release_object( async );
634 set_error( STATUS_PENDING );
Alexandre Julliard63a23722007-05-03 17:44:05 +0200635 return wait_handle;
Alexandre Julliard6105a932007-04-18 16:26:37 +0200636 }
637 break;
638 case ps_connected_server:
639 set_error( STATUS_PIPE_CONNECTED );
640 break;
641 case ps_disconnected_server:
642 set_error( STATUS_PIPE_BUSY );
643 break;
644 case ps_wait_disconnect:
645 set_error( STATUS_NO_DATA_DETECTED );
646 break;
647 case ps_wait_open:
648 set_error( STATUS_INVALID_HANDLE );
649 break;
650 }
Alexandre Julliardfd59e152007-05-03 17:43:18 +0200651 return 0;
Alexandre Julliard6105a932007-04-18 16:26:37 +0200652
Alexandre Julliard8c460952007-04-16 14:51:29 +0200653 case FSCTL_PIPE_DISCONNECT:
654 switch(server->state)
655 {
656 case ps_connected_server:
657 assert( server->client );
658 assert( server->client->fd );
659
660 notify_empty( server );
661
662 /* dump the client and server fds, but keep the pointers
663 around - client loses all waiting data */
Alexandre Julliard8c460952007-04-16 14:51:29 +0200664 do_disconnect( server );
Alexandre Julliard6105a932007-04-18 16:26:37 +0200665 set_server_state( server, ps_disconnected_server );
Alexandre Julliard8c460952007-04-16 14:51:29 +0200666 break;
667 case ps_wait_disconnect:
668 assert( !server->client );
669 do_disconnect( server );
Alexandre Julliard6105a932007-04-18 16:26:37 +0200670 set_server_state( server, ps_wait_connect );
Alexandre Julliard8c460952007-04-16 14:51:29 +0200671 break;
672 case ps_idle_server:
673 case ps_wait_open:
Alexandre Julliard6105a932007-04-18 16:26:37 +0200674 set_error( STATUS_PIPE_LISTENING );
675 break;
Alexandre Julliard8c460952007-04-16 14:51:29 +0200676 case ps_disconnected_server:
677 case ps_wait_connect:
Alexandre Julliard6105a932007-04-18 16:26:37 +0200678 set_error( STATUS_PIPE_DISCONNECTED );
Alexandre Julliard8c460952007-04-16 14:51:29 +0200679 break;
680 }
Alexandre Julliardfd59e152007-05-03 17:43:18 +0200681 return 0;
Alexandre Julliard6105a932007-04-18 16:26:37 +0200682
Alexandre Julliard8c460952007-04-16 14:51:29 +0200683 default:
Alexandre Julliard7ec95c52008-12-30 20:37:20 +0100684 return default_fd_ioctl( fd, code, async_data, blocking, data, size );
Alexandre Julliard8c460952007-04-16 14:51:29 +0200685 }
686}
687
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100688static struct named_pipe *create_named_pipe( struct directory *root, const struct unicode_str *name,
689 unsigned int attr )
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000690{
691 struct object *obj;
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100692 struct named_pipe *pipe = NULL;
693 struct unicode_str new_name;
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000694
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100695 if (!name || !name->len) return alloc_object( &named_pipe_ops );
696
Alexandre Julliard50c48002007-03-22 14:40:41 +0100697 if (!(obj = find_object_dir( root, name, attr, &new_name )))
698 {
699 set_error( STATUS_OBJECT_NAME_INVALID );
700 return NULL;
701 }
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100702 if (!new_name.len)
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000703 {
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100704 if (attr & OBJ_OPENIF && obj->ops == &named_pipe_ops)
705 set_error( STATUS_OBJECT_NAME_EXISTS );
706 else
707 {
708 release_object( obj );
709 obj = NULL;
710 if (attr & OBJ_OPENIF)
711 set_error( STATUS_OBJECT_TYPE_MISMATCH );
712 else
713 set_error( STATUS_OBJECT_NAME_COLLISION );
714 }
715 return (struct named_pipe *)obj;
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000716 }
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000717
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100718 if (obj->ops != &named_pipe_device_ops)
Alexandre Julliard50c48002007-03-22 14:40:41 +0100719 set_error( STATUS_OBJECT_NAME_INVALID );
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100720 else
721 {
722 struct named_pipe_device *dev = (struct named_pipe_device *)obj;
723 if ((pipe = create_object( dev->pipes, &named_pipe_ops, &new_name, NULL )))
724 clear_error();
725 }
726
727 release_object( obj );
728 return pipe;
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000729}
730
Mike McCormackef8b9462003-05-15 04:22:45 +0000731static struct pipe_server *get_pipe_server_obj( struct process *process,
732 obj_handle_t handle, unsigned int access )
Mike McCormackde7c3002001-07-10 19:16:49 +0000733{
Mike McCormackef8b9462003-05-15 04:22:45 +0000734 struct object *obj;
735 obj = get_handle_obj( process, handle, access, &pipe_server_ops );
736 return (struct pipe_server *) obj;
Mike McCormackde7c3002001-07-10 19:16:49 +0000737}
738
Robert Shearmane51dd362005-06-08 19:11:46 +0000739static struct pipe_server *create_pipe_server( struct named_pipe *pipe, unsigned int options )
Mike McCormackde7c3002001-07-10 19:16:49 +0000740{
Mike McCormackef8b9462003-05-15 04:22:45 +0000741 struct pipe_server *server;
Mike McCormackde7c3002001-07-10 19:16:49 +0000742
Mike McCormackef8b9462003-05-15 04:22:45 +0000743 server = alloc_object( &pipe_server_ops );
Robert Shearman37957092005-06-10 19:54:46 +0000744 if (!server)
Mike McCormackde7c3002001-07-10 19:16:49 +0000745 return NULL;
Mike McCormackde7c3002001-07-10 19:16:49 +0000746
Mike McCormackef8b9462003-05-15 04:22:45 +0000747 server->fd = NULL;
748 server->pipe = pipe;
Mike McCormackef8b9462003-05-15 04:22:45 +0000749 server->client = NULL;
750 server->flush_poll = NULL;
Robert Shearmane51dd362005-06-08 19:11:46 +0000751 server->options = options;
Mike McCormackde7c3002001-07-10 19:16:49 +0000752
Alexandre Julliard7c1cf8f2005-02-03 10:48:23 +0000753 list_add_head( &pipe->servers, &server->entry );
Mike McCormackef8b9462003-05-15 04:22:45 +0000754 grab_object( pipe );
Alexandre Julliard017480d2007-05-03 16:07:30 +0200755 if (!(server->ioctl_fd = alloc_pseudo_fd( &pipe_server_fd_ops, &server->obj, options )))
Alexandre Julliard6105a932007-04-18 16:26:37 +0200756 {
757 release_object( server );
Marcus Meissnerfea59c82007-05-08 21:13:14 +0200758 return NULL;
Alexandre Julliard6105a932007-04-18 16:26:37 +0200759 }
760 set_server_state( server, ps_idle_server );
Mike McCormackef8b9462003-05-15 04:22:45 +0000761 return server;
Mike McCormackde7c3002001-07-10 19:16:49 +0000762}
763
Robert Shearman43890d82006-06-07 20:11:59 +0100764static struct pipe_client *create_pipe_client( unsigned int flags )
Mike McCormackde7c3002001-07-10 19:16:49 +0000765{
Mike McCormackef8b9462003-05-15 04:22:45 +0000766 struct pipe_client *client;
Mike McCormackde7c3002001-07-10 19:16:49 +0000767
Mike McCormackef8b9462003-05-15 04:22:45 +0000768 client = alloc_object( &pipe_client_ops );
Robert Shearman37957092005-06-10 19:54:46 +0000769 if (!client)
Mike McCormackbf554572001-08-23 23:29:20 +0000770 return NULL;
771
Mike McCormackef8b9462003-05-15 04:22:45 +0000772 client->fd = NULL;
Robert Shearman43890d82006-06-07 20:11:59 +0100773 client->server = NULL;
Robert Shearmane51dd362005-06-08 19:11:46 +0000774 client->flags = flags;
Mike McCormackef8b9462003-05-15 04:22:45 +0000775
776 return client;
777}
778
Alexandre Julliard73e0e8b2007-03-23 14:03:23 +0100779static struct pipe_server *find_available_server( struct named_pipe *pipe )
Mike McCormackef8b9462003-05-15 04:22:45 +0000780{
Alexandre Julliard7c1cf8f2005-02-03 10:48:23 +0000781 struct pipe_server *server;
Mike McCormackef8b9462003-05-15 04:22:45 +0000782
Rob Shearman44581af2008-02-04 20:18:34 +0000783 /* look for pipe servers that are listening */
Alexandre Julliard7c1cf8f2005-02-03 10:48:23 +0000784 LIST_FOR_EACH_ENTRY( server, &pipe->servers, struct pipe_server, entry )
785 {
Rob Shearman44581af2008-02-04 20:18:34 +0000786 if (server->state == ps_wait_open)
Alexandre Julliard7c1cf8f2005-02-03 10:48:23 +0000787 return (struct pipe_server *)grab_object( server );
788 }
Rob Shearman44581af2008-02-04 20:18:34 +0000789
790 /* fall back to pipe servers that are idle */
791 LIST_FOR_EACH_ENTRY( server, &pipe->servers, struct pipe_server, entry )
792 {
793 if (server->state == ps_idle_server)
794 return (struct pipe_server *)grab_object( server );
795 }
796
Alexandre Julliard7c1cf8f2005-02-03 10:48:23 +0000797 return NULL;
Mike McCormackde7c3002001-07-10 19:16:49 +0000798}
799
Alexandre Julliardde1866d2007-03-22 16:47:46 +0100800static struct object *named_pipe_open_file( struct object *obj, unsigned int access,
801 unsigned int sharing, unsigned int options )
802{
803 struct named_pipe *pipe = (struct named_pipe *)obj;
804 struct pipe_server *server;
805 struct pipe_client *client;
806 int fds[2];
807
Alexandre Julliard73e0e8b2007-03-23 14:03:23 +0100808 if (!(server = find_available_server( pipe )))
Alexandre Julliardde1866d2007-03-22 16:47:46 +0100809 {
810 set_error( STATUS_PIPE_NOT_AVAILABLE );
811 return NULL;
812 }
813
814 if ((client = create_pipe_client( options )))
815 {
816 if (!socketpair( PF_UNIX, SOCK_STREAM, 0, fds ))
817 {
Alexandre Julliardde1866d2007-03-22 16:47:46 +0100818 assert( !server->fd );
819
820 /* for performance reasons, only set nonblocking mode when using
821 * overlapped I/O. Otherwise, we will be doing too much busy
822 * looping */
Alexandre Julliard6105a932007-04-18 16:26:37 +0200823 if (is_overlapped( options )) fcntl( fds[1], F_SETFL, O_NONBLOCK );
824 if (is_overlapped( server->options )) fcntl( fds[0], F_SETFL, O_NONBLOCK );
Alexandre Julliardde1866d2007-03-22 16:47:46 +0100825
826 if (pipe->insize)
827 {
828 setsockopt( fds[0], SOL_SOCKET, SO_RCVBUF, &pipe->insize, sizeof(pipe->insize) );
829 setsockopt( fds[1], SOL_SOCKET, SO_RCVBUF, &pipe->insize, sizeof(pipe->insize) );
830 }
831 if (pipe->outsize)
832 {
833 setsockopt( fds[0], SOL_SOCKET, SO_SNDBUF, &pipe->outsize, sizeof(pipe->outsize) );
834 setsockopt( fds[1], SOL_SOCKET, SO_SNDBUF, &pipe->outsize, sizeof(pipe->outsize) );
835 }
836
Alexandre Julliardf85437c2007-04-10 22:25:07 +0200837 client->fd = create_anonymous_fd( &pipe_client_fd_ops, fds[1], &client->obj, options );
838 server->fd = create_anonymous_fd( &pipe_server_fd_ops, fds[0], &server->obj, server->options );
Alexandre Julliard6105a932007-04-18 16:26:37 +0200839 if (client->fd && server->fd)
Alexandre Julliardde1866d2007-03-22 16:47:46 +0100840 {
Alexandre Julliard50171c52009-03-02 20:34:39 +0100841 fd_copy_completion( server->ioctl_fd, server->fd );
Alexandre Julliardde1866d2007-03-22 16:47:46 +0100842 if (server->state == ps_wait_open)
Alexandre Julliardc18e8d62007-04-18 16:28:01 +0200843 fd_async_wake_up( server->ioctl_fd, ASYNC_TYPE_WAIT, STATUS_SUCCESS );
Alexandre Julliard6105a932007-04-18 16:26:37 +0200844 set_server_state( server, ps_connected_server );
Alexandre Julliardde1866d2007-03-22 16:47:46 +0100845 server->client = client;
846 client->server = server;
847 }
Alexandre Julliard6105a932007-04-18 16:26:37 +0200848 else
849 {
850 release_object( client );
851 client = NULL;
852 }
Alexandre Julliardde1866d2007-03-22 16:47:46 +0100853 }
854 else
Alexandre Julliard6105a932007-04-18 16:26:37 +0200855 {
Alexandre Julliardde1866d2007-03-22 16:47:46 +0100856 file_set_error();
Alexandre Julliard6105a932007-04-18 16:26:37 +0200857 release_object( client );
858 client = NULL;
859 }
Alexandre Julliardde1866d2007-03-22 16:47:46 +0100860 }
861 release_object( server );
862 return &client->obj;
863}
864
Alexandre Julliardfd59e152007-05-03 17:43:18 +0200865static obj_handle_t named_pipe_device_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data,
Alexandre Julliard7ec95c52008-12-30 20:37:20 +0100866 int blocking, const void *data, data_size_t size )
Alexandre Julliard3684dc12007-04-17 22:07:07 +0200867{
868 struct named_pipe_device *device = get_fd_user( fd );
869
870 switch(code)
871 {
872 case FSCTL_PIPE_WAIT:
873 {
874 const FILE_PIPE_WAIT_FOR_BUFFER *buffer = data;
Alexandre Julliard46fe7172007-05-03 17:44:32 +0200875 obj_handle_t wait_handle = 0;
Alexandre Julliard3684dc12007-04-17 22:07:07 +0200876 struct named_pipe *pipe;
877 struct pipe_server *server;
878 struct unicode_str name;
879
880 if (size < sizeof(*buffer) ||
881 size < FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name[buffer->NameLength/sizeof(WCHAR)]))
882 {
883 set_error( STATUS_INVALID_PARAMETER );
Alexandre Julliardfd59e152007-05-03 17:43:18 +0200884 return 0;
Alexandre Julliard3684dc12007-04-17 22:07:07 +0200885 }
886 name.str = buffer->Name;
887 name.len = (buffer->NameLength / sizeof(WCHAR)) * sizeof(WCHAR);
888 if (!(pipe = (struct named_pipe *)find_object( device->pipes, &name, OBJ_CASE_INSENSITIVE )))
889 {
890 set_error( STATUS_PIPE_NOT_AVAILABLE );
Alexandre Julliardfd59e152007-05-03 17:43:18 +0200891 return 0;
Alexandre Julliard3684dc12007-04-17 22:07:07 +0200892 }
893 if (!(server = find_available_server( pipe )))
894 {
895 struct async *async;
896
Alexandre Julliard46fe7172007-05-03 17:44:32 +0200897 if (!pipe->waiters && !(pipe->waiters = create_async_queue( NULL ))) goto done;
Alexandre Julliard3684dc12007-04-17 22:07:07 +0200898
Alexandre Julliard7ec95c52008-12-30 20:37:20 +0100899 if (blocking)
Alexandre Julliard46fe7172007-05-03 17:44:32 +0200900 {
901 async_data_t new_data = *async_data;
902 if (!(wait_handle = alloc_wait_event( current->process ))) goto done;
903 new_data.event = wait_handle;
904 if (!(async = create_async( current, pipe->waiters, &new_data )))
905 {
906 close_handle( current->process, wait_handle );
907 wait_handle = 0;
908 }
909 }
910 else async = create_async( current, pipe->waiters, async_data );
911
912 if (async)
Alexandre Julliard3684dc12007-04-17 22:07:07 +0200913 {
914 timeout_t when = buffer->TimeoutSpecified ? buffer->Timeout.QuadPart : pipe->timeout;
915 async_set_timeout( async, when, STATUS_IO_TIMEOUT );
916 release_object( async );
917 set_error( STATUS_PENDING );
918 }
919 }
920 else release_object( server );
921
Alexandre Julliard46fe7172007-05-03 17:44:32 +0200922 done:
Alexandre Julliard3684dc12007-04-17 22:07:07 +0200923 release_object( pipe );
Alexandre Julliard46fe7172007-05-03 17:44:32 +0200924 return wait_handle;
Alexandre Julliard3684dc12007-04-17 22:07:07 +0200925 }
926
927 default:
Alexandre Julliard7ec95c52008-12-30 20:37:20 +0100928 return default_fd_ioctl( fd, code, async_data, blocking, data, size );
Alexandre Julliard3684dc12007-04-17 22:07:07 +0200929 }
930}
931
932
Mike McCormackde7c3002001-07-10 19:16:49 +0000933DECL_HANDLER(create_named_pipe)
934{
935 struct named_pipe *pipe;
Mike McCormackef8b9462003-05-15 04:22:45 +0000936 struct pipe_server *server;
Alexandre Julliardead9b062005-11-18 16:31:18 +0000937 struct unicode_str name;
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100938 struct directory *root = NULL;
Mike McCormackde7c3002001-07-10 19:16:49 +0000939
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000940 reply->handle = 0;
Alexandre Julliardead9b062005-11-18 16:31:18 +0000941 get_req_unicode_str( &name );
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100942 if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 )))
943 return;
944
945 pipe = create_named_pipe( root, &name, req->attributes | OBJ_OPENIF );
946
947 if (root) release_object( root );
948 if (!pipe) return;
Mike McCormackde7c3002001-07-10 19:16:49 +0000949
Vitaliy Margolen893987b2005-11-21 16:27:03 +0000950 if (get_error() != STATUS_OBJECT_NAME_EXISTS)
Mike McCormackf2e7ce72001-08-27 19:03:42 +0000951 {
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100952 /* initialize it if it didn't already exist */
953 pipe->instances = 0;
Alexandre Julliarddf09ac52007-04-02 20:09:29 +0200954 pipe->waiters = NULL;
Vitaliy Margolenbabfa792005-12-05 13:09:35 +0100955 list_init( &pipe->servers );
Mike McCormackf2e7ce72001-08-27 19:03:42 +0000956 pipe->insize = req->insize;
957 pipe->outsize = req->outsize;
958 pipe->maxinstances = req->maxinstances;
959 pipe->timeout = req->timeout;
Eric Pouech5a2591d2005-04-18 14:57:04 +0000960 pipe->flags = req->flags;
Mike McCormackf2e7ce72001-08-27 19:03:42 +0000961 }
Mike McCormackef8b9462003-05-15 04:22:45 +0000962 else
Mike McCormackde7c3002001-07-10 19:16:49 +0000963 {
Robert Shearman37957092005-06-10 19:54:46 +0000964 if (pipe->maxinstances <= pipe->instances)
Mike McCormackef8b9462003-05-15 04:22:45 +0000965 {
Vitaliy Margolenecca1042005-11-01 21:37:30 +0000966 set_error( STATUS_INSTANCE_NOT_AVAILABLE );
Mike McCormackef8b9462003-05-15 04:22:45 +0000967 release_object( pipe );
968 return;
969 }
Robert Shearman37957092005-06-10 19:54:46 +0000970 if ((pipe->maxinstances != req->maxinstances) ||
971 (pipe->timeout != req->timeout) ||
972 (pipe->flags != req->flags))
Mike McCormackef8b9462003-05-15 04:22:45 +0000973 {
974 set_error( STATUS_ACCESS_DENIED );
975 release_object( pipe );
976 return;
977 }
Eric Pouech1d6e2592006-05-26 12:10:11 +0200978 clear_error(); /* clear the name collision */
Mike McCormackef8b9462003-05-15 04:22:45 +0000979 }
980
Robert Shearmane51dd362005-06-08 19:11:46 +0000981 server = create_pipe_server( pipe, req->options );
Robert Shearman37957092005-06-10 19:54:46 +0000982 if (server)
Mike McCormackef8b9462003-05-15 04:22:45 +0000983 {
Alexandre Julliard24560e72005-12-09 13:58:25 +0100984 reply->handle = alloc_handle( current->process, server, req->access, req->attributes );
Mike McCormackef8b9462003-05-15 04:22:45 +0000985 server->pipe->instances++;
986 release_object( server );
Mike McCormackde7c3002001-07-10 19:16:49 +0000987 }
988
989 release_object( pipe );
990}
991
Mike McCormackf2e7ce72001-08-27 19:03:42 +0000992DECL_HANDLER(get_named_pipe_info)
993{
Mike McCormackef8b9462003-05-15 04:22:45 +0000994 struct pipe_server *server;
Eric Pouech1d6e2592006-05-26 12:10:11 +0200995 struct pipe_client *client = NULL;
Mike McCormackf2e7ce72001-08-27 19:03:42 +0000996
Eric Pouech1d6e2592006-05-26 12:10:11 +0200997 server = get_pipe_server_obj( current->process, req->handle, FILE_READ_ATTRIBUTES );
Robert Shearman37957092005-06-10 19:54:46 +0000998 if (!server)
Eric Pouech1d6e2592006-05-26 12:10:11 +0200999 {
1000 clear_error();
1001 client = (struct pipe_client *)get_handle_obj( current->process, req->handle,
1002 FILE_READ_ATTRIBUTES, &pipe_client_ops );
1003 if (!client) return;
1004 server = client->server;
1005 }
Mike McCormackf2e7ce72001-08-27 19:03:42 +00001006
Eric Pouech5a2591d2005-04-18 14:57:04 +00001007 reply->flags = server->pipe->flags;
Mike McCormackef8b9462003-05-15 04:22:45 +00001008 reply->maxinstances = server->pipe->maxinstances;
Eric Pouech1d6e2592006-05-26 12:10:11 +02001009 reply->instances = server->pipe->instances;
Mike McCormackef8b9462003-05-15 04:22:45 +00001010 reply->insize = server->pipe->insize;
1011 reply->outsize = server->pipe->outsize;
Mike McCormackf2e7ce72001-08-27 19:03:42 +00001012
Eric Pouech1d6e2592006-05-26 12:10:11 +02001013 if (client)
1014 release_object(client);
1015 else
1016 {
1017 reply->flags |= NAMED_PIPE_SERVER_END;
1018 release_object(server);
1019 }
Mike McCormackf2e7ce72001-08-27 19:03:42 +00001020}