2 * Server-side pipe management
4 * Copyright (C) 1998 Alexandre Julliard
5 * Copyright (C) 2001 Mike McCormack
8 * improve error handling
19 #include <sys/types.h>
20 #include <sys/socket.h>
46 enum pipe_state state;
47 struct pipe_user *other;
48 struct named_pipe *pipe;
49 struct pipe_user *next;
50 struct pipe_user *prev;
56 struct object obj; /* object header */
57 unsigned int pipemode;
58 unsigned int maxinstances;
62 struct pipe_user *users;
65 static void named_pipe_dump( struct object *obj, int verbose );
66 static void named_pipe_destroy( struct object *obj);
68 static const struct object_ops named_pipe_ops =
70 sizeof(struct named_pipe), /* size */
71 named_pipe_dump, /* dump */
72 no_add_queue, /* add_queue */
73 NULL, /* remove_queue */
76 NULL, /* get_poll_events */
77 NULL, /* poll_event */
78 no_get_fd, /* get_fd */
80 no_get_file_info, /* get_file_info */
81 named_pipe_destroy /* destroy */
84 static void pipe_user_dump( struct object *obj, int verbose );
85 static void pipe_user_destroy( struct object *obj);
86 static int pipe_user_get_fd( struct object *obj );
87 static int pipe_user_get_info( struct object *obj, struct get_file_info_request *req );
89 static const struct object_ops pipe_user_ops =
91 sizeof(struct pipe_user), /* size */
92 pipe_user_dump, /* dump */
93 default_poll_add_queue, /* add_queue */
94 default_poll_remove_queue, /* remove_queue */
95 default_poll_signaled, /* signaled */
96 no_satisfied, /* satisfied */
97 NULL, /* get_poll_events */
98 default_poll_event, /* poll_event */
99 pipe_user_get_fd, /* get_fd */
100 no_flush, /* flush */
101 pipe_user_get_info, /* get_file_info */
102 pipe_user_destroy /* destroy */
105 static void named_pipe_dump( struct object *obj, int verbose )
107 struct named_pipe *pipe = (struct named_pipe *)obj;
108 assert( obj->ops == &named_pipe_ops );
109 fprintf( stderr, "named pipe %p\n" ,pipe);
112 static void pipe_user_dump( struct object *obj, int verbose )
114 struct pipe_user *user = (struct pipe_user *)obj;
115 assert( obj->ops == &pipe_user_ops );
116 fprintf( stderr, "named pipe user %p (state %d)\n", user, user->state );
119 static void named_pipe_destroy( struct object *obj)
121 struct named_pipe *pipe = (struct named_pipe *)obj;
122 assert( !pipe->users );
125 static void pipe_user_destroy( struct object *obj)
127 struct pipe_user *user = (struct pipe_user *)obj;
129 assert( obj->ops == &pipe_user_ops );
133 /* FIXME: signal waiter of failure */
134 release_object(user->event);
139 close(user->other->obj.fd);
140 user->other->obj.fd = -1;
141 switch(user->other->state)
143 case ps_connected_server:
144 user->other->state = ps_idle_server;
146 case ps_connected_client:
147 user->other->state = ps_disconnected;
150 fprintf(stderr,"connected pipe has strange state %d!\n",
153 user->other->other=NULL;
157 /* remove user from pipe's user list */
158 if (user->next) user->next->prev = user->prev;
159 if (user->prev) user->prev->next = user->next;
160 else user->pipe->users = user->next;
161 release_object(user->pipe);
164 static int pipe_user_get_fd( struct object *obj )
166 struct pipe_user *user = (struct pipe_user *)obj;
167 assert( obj->ops == &pipe_user_ops );
171 static int pipe_user_get_info( struct object *obj, struct get_file_info_request *req )
175 req->type = FILE_TYPE_PIPE;
177 req->access_time = 0;
186 return FD_TYPE_DEFAULT;
189 static struct named_pipe *create_named_pipe( const WCHAR *name, size_t len )
191 struct named_pipe *pipe;
193 if ((pipe = create_named_object( &named_pipe_ops, name, len )))
195 if (get_error() != STATUS_OBJECT_NAME_COLLISION)
197 /* initialize it if it didn't already exist */
204 static struct pipe_user *get_pipe_user_obj( struct process *process, handle_t handle,
205 unsigned int access )
207 return (struct pipe_user *)get_handle_obj( process, handle, access, &pipe_user_ops );
210 static struct pipe_user *create_pipe_user( struct named_pipe *pipe, int fd )
212 struct pipe_user *user;
214 user = alloc_object( &pipe_user_ops, fd );
219 user->state = ps_none;
220 user->event = NULL; /* thread wait on this pipe */
223 /* add to list of pipe users */
224 if ((user->next = pipe->users)) user->next->prev = user;
233 static struct pipe_user *find_partner(struct named_pipe *pipe, enum pipe_state state)
237 for(x = pipe->users; x; x=x->next)
246 return (struct pipe_user *)grab_object( x );
249 DECL_HANDLER(create_named_pipe)
251 struct named_pipe *pipe;
252 struct pipe_user *user;
255 pipe = create_named_pipe( get_req_data(req), get_req_data_size(req) );
259 if (get_error() != STATUS_OBJECT_NAME_COLLISION)
261 pipe->insize = req->insize;
262 pipe->outsize = req->outsize;
263 pipe->maxinstances = req->maxinstances;
264 pipe->timeout = req->timeout;
265 pipe->pipemode = req->pipemode;
268 user = create_pipe_user (pipe, -1);
272 user->state = ps_idle_server;
273 req->handle = alloc_handle( current->process, user, GENERIC_READ|GENERIC_WRITE, 0 );
274 release_object( user );
277 release_object( pipe );
280 DECL_HANDLER(open_named_pipe)
282 struct named_pipe *pipe;
285 pipe = create_named_pipe( get_req_data(req), get_req_data_size(req) );
289 if (get_error() == STATUS_OBJECT_NAME_COLLISION)
291 struct pipe_user *partner;
293 if ((partner = find_partner(pipe, ps_wait_open)))
297 if(!socketpair(PF_UNIX, SOCK_STREAM, 0, fds))
299 struct pipe_user *user;
301 if( (user = create_pipe_user (pipe, fds[1])) )
303 partner->obj.fd = fds[0];
304 set_event(partner->event);
305 release_object(partner->event);
306 partner->event = NULL;
307 partner->state = ps_connected_server;
308 partner->other = user;
309 user->state = ps_connected_client;
310 user->other = partner;
311 req->handle = alloc_handle( current->process, user, req->access, 0 );
312 release_object(user);
319 release_object( partner );
323 set_error(STATUS_PIPE_NOT_AVAILABLE);
328 set_error(STATUS_NO_SUCH_FILE);
331 release_object(pipe);
334 DECL_HANDLER(connect_named_pipe)
336 struct pipe_user *user, *partner;
339 user = get_pipe_user_obj(current->process, req->handle, 0);
343 if( user->state != ps_idle_server )
345 set_error(STATUS_PORT_ALREADY_SET);
349 user->state = ps_wait_open;
350 event = get_event_obj(current->process, req->event, 0);
354 /* notify all waiters that a pipe just became available */
355 while( (partner = find_partner(user->pipe,ps_wait_connect)) )
357 set_event(partner->event);
358 release_object(partner->event);
359 partner->event = NULL;
360 release_object(partner);
361 release_object(partner);
365 release_object(user);
368 DECL_HANDLER(wait_named_pipe)
371 struct named_pipe *pipe;
373 event = get_event_obj(current->process, req->event, 0);
377 pipe = create_named_pipe( get_req_data(req), get_req_data_size(req) );
380 /* only wait if the pipe already exists */
381 if(get_error() == STATUS_OBJECT_NAME_COLLISION)
383 struct pipe_user *partner;
385 set_error(STATUS_SUCCESS);
386 if( (partner = find_partner(pipe,ps_wait_open)) )
389 release_object(partner);
393 struct pipe_user *user;
395 if( (user = create_pipe_user (pipe, -1)) )
397 user->event = (struct event *)grab_object( event );
398 user->state = ps_wait_connect;
399 /* don't release it */
405 set_error(STATUS_PIPE_NOT_AVAILABLE);
407 release_object(pipe);
409 release_object(event);
412 DECL_HANDLER(disconnect_named_pipe)
414 struct pipe_user *user;
416 user = get_pipe_user_obj(current->process, req->handle, 0);
419 if( (user->state == ps_connected_server) &&
420 (user->other->state == ps_connected_client) )
422 close(user->other->obj.fd);
423 user->other->obj.fd = -1;
424 user->other->state = ps_disconnected;
425 user->other->other = NULL;
429 user->state = ps_idle_server;
432 release_object(user);
435 DECL_HANDLER(get_named_pipe_info)
437 struct pipe_user *user;
439 user = get_pipe_user_obj(current->process, req->handle, 0);
443 req->flags = user->pipe->pipemode;
444 req->maxinstances = user->pipe->maxinstances;
445 req->insize = user->pipe->insize;
446 req->outsize = user->pipe->outsize;
448 release_object(user);