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;
58 struct object obj; /* object header */
59 unsigned int pipemode;
60 unsigned int maxinstances;
64 struct pipe_user *users;
67 static void named_pipe_dump( struct object *obj, int verbose );
68 static void named_pipe_destroy( struct object *obj);
70 static const struct object_ops named_pipe_ops =
72 sizeof(struct named_pipe), /* size */
73 named_pipe_dump, /* dump */
74 no_add_queue, /* add_queue */
75 NULL, /* remove_queue */
78 NULL, /* get_poll_events */
79 NULL, /* poll_event */
80 no_get_fd, /* get_fd */
82 no_get_file_info, /* get_file_info */
83 named_pipe_destroy /* destroy */
86 static void pipe_user_dump( struct object *obj, int verbose );
87 static void pipe_user_destroy( struct object *obj);
88 static int pipe_user_get_fd( struct object *obj );
89 static int pipe_user_get_info( struct object *obj, struct get_file_info_request *req );
91 static const struct object_ops pipe_user_ops =
93 sizeof(struct pipe_user), /* size */
94 pipe_user_dump, /* dump */
95 default_poll_add_queue, /* add_queue */
96 default_poll_remove_queue, /* remove_queue */
97 default_poll_signaled, /* signaled */
98 no_satisfied, /* satisfied */
99 NULL, /* get_poll_events */
100 default_poll_event, /* poll_event */
101 pipe_user_get_fd, /* get_fd */
102 no_flush, /* flush */
103 pipe_user_get_info, /* get_file_info */
104 pipe_user_destroy /* destroy */
107 static void named_pipe_dump( struct object *obj, int verbose )
109 struct named_pipe *pipe = (struct named_pipe *)obj;
110 assert( obj->ops == &named_pipe_ops );
111 fprintf( stderr, "named pipe %p\n" ,pipe);
114 static void pipe_user_dump( struct object *obj, int verbose )
116 struct pipe_user *user = (struct pipe_user *)obj;
117 assert( obj->ops == &pipe_user_ops );
118 fprintf( stderr, "named pipe user %p (state %d)\n", user, user->state );
121 static void named_pipe_destroy( struct object *obj)
123 struct named_pipe *pipe = (struct named_pipe *)obj;
124 assert( !pipe->users );
127 static void notify_waiter( struct pipe_user *user, unsigned int status)
129 if(user->thread && user->func && user->overlapped)
131 /* queue a system APC, to notify a waiting thread */
132 thread_queue_apc(user->thread,NULL,user->func,
133 APC_ASYNC,1,2,user->overlapped,status);
137 user->overlapped=NULL;
140 static void pipe_user_destroy( struct object *obj)
142 struct pipe_user *user = (struct pipe_user *)obj;
144 assert( obj->ops == &pipe_user_ops );
147 notify_waiter(user,STATUS_HANDLES_CLOSED);
151 close(user->other->obj.fd);
152 user->other->obj.fd = -1;
153 switch(user->other->state)
155 case ps_connected_server:
156 user->other->state = ps_idle_server;
158 case ps_connected_client:
159 user->other->state = ps_disconnected;
162 fprintf(stderr,"connected pipe has strange state %d!\n",
165 user->other->other=NULL;
169 /* remove user from pipe's user list */
170 if (user->next) user->next->prev = user->prev;
171 if (user->prev) user->prev->next = user->next;
172 else user->pipe->users = user->next;
173 release_object(user->pipe);
176 static int pipe_user_get_fd( struct object *obj )
178 struct pipe_user *user = (struct pipe_user *)obj;
179 assert( obj->ops == &pipe_user_ops );
183 static int pipe_user_get_info( struct object *obj, struct get_file_info_request *req )
187 req->type = FILE_TYPE_PIPE;
189 req->access_time = 0;
198 return FD_TYPE_DEFAULT;
201 static struct named_pipe *create_named_pipe( const WCHAR *name, size_t len )
203 struct named_pipe *pipe;
205 if ((pipe = create_named_object( &named_pipe_ops, name, len )))
207 if (get_error() != STATUS_OBJECT_NAME_COLLISION)
209 /* initialize it if it didn't already exist */
216 static struct pipe_user *get_pipe_user_obj( struct process *process, handle_t handle,
217 unsigned int access )
219 return (struct pipe_user *)get_handle_obj( process, handle, access, &pipe_user_ops );
222 static struct pipe_user *create_pipe_user( struct named_pipe *pipe, int fd )
224 struct pipe_user *user;
226 user = alloc_object( &pipe_user_ops, fd );
231 user->state = ps_none;
235 user->overlapped = NULL;
237 /* add to list of pipe users */
238 if ((user->next = pipe->users)) user->next->prev = user;
247 static struct pipe_user *find_partner(struct named_pipe *pipe, enum pipe_state state)
251 for(x = pipe->users; x; x=x->next)
260 return (struct pipe_user *)grab_object( x );
263 DECL_HANDLER(create_named_pipe)
265 struct named_pipe *pipe;
266 struct pipe_user *user;
269 pipe = create_named_pipe( get_req_data(req), get_req_data_size(req) );
273 if (get_error() != STATUS_OBJECT_NAME_COLLISION)
275 pipe->insize = req->insize;
276 pipe->outsize = req->outsize;
277 pipe->maxinstances = req->maxinstances;
278 pipe->timeout = req->timeout;
279 pipe->pipemode = req->pipemode;
282 user = create_pipe_user (pipe, -1);
286 user->state = ps_idle_server;
287 req->handle = alloc_handle( current->process, user, GENERIC_READ|GENERIC_WRITE, 0 );
288 release_object( user );
291 release_object( pipe );
294 DECL_HANDLER(open_named_pipe)
296 struct named_pipe *pipe;
299 pipe = create_named_pipe( get_req_data(req), get_req_data_size(req) );
303 if (get_error() == STATUS_OBJECT_NAME_COLLISION)
305 struct pipe_user *partner;
307 if ((partner = find_partner(pipe, ps_wait_open)))
311 if(!socketpair(PF_UNIX, SOCK_STREAM, 0, fds))
313 struct pipe_user *user;
315 if( (user = create_pipe_user (pipe, fds[1])) )
317 partner->obj.fd = fds[0];
318 notify_waiter(partner,STATUS_SUCCESS);
319 partner->state = ps_connected_server;
320 partner->other = user;
321 user->state = ps_connected_client;
322 user->other = partner;
323 req->handle = alloc_handle( current->process, user, req->access, 0 );
324 release_object(user);
331 release_object( partner );
335 set_error(STATUS_PIPE_NOT_AVAILABLE);
340 set_error(STATUS_NO_SUCH_FILE);
343 release_object(pipe);
346 DECL_HANDLER(connect_named_pipe)
348 struct pipe_user *user, *partner;
350 user = get_pipe_user_obj(current->process, req->handle, 0);
354 if( user->state != ps_idle_server )
356 set_error(STATUS_PORT_ALREADY_SET);
360 user->state = ps_wait_open;
361 user->thread = current;
362 user->func = req->func;
363 user->overlapped = req->overlapped;
365 /* notify all waiters that a pipe just became available */
366 while( (partner = find_partner(user->pipe,ps_wait_connect)) )
368 notify_waiter(partner,STATUS_SUCCESS);
369 release_object(partner);
370 release_object(partner);
374 release_object(user);
377 DECL_HANDLER(wait_named_pipe)
379 struct named_pipe *pipe;
381 pipe = create_named_pipe( get_req_data(req), get_req_data_size(req) );
384 /* only wait if the pipe already exists */
385 if(get_error() == STATUS_OBJECT_NAME_COLLISION)
387 struct pipe_user *partner;
389 set_error(STATUS_SUCCESS);
390 if( (partner = find_partner(pipe,ps_wait_open)) )
392 /* this should use notify_waiter,
393 but no pipe_user object exists now... */
394 thread_queue_apc(current,NULL,req->func,
395 APC_ASYNC,1,2,req->overlapped,STATUS_SUCCESS);
396 release_object(partner);
400 struct pipe_user *user;
402 if( (user = create_pipe_user (pipe, -1)) )
404 user->state = ps_wait_connect;
405 user->thread = current;
406 user->func = req->func;
407 user->overlapped = req->overlapped;
408 /* don't release it */
414 set_error(STATUS_PIPE_NOT_AVAILABLE);
416 release_object(pipe);
420 DECL_HANDLER(disconnect_named_pipe)
422 struct pipe_user *user;
424 user = get_pipe_user_obj(current->process, req->handle, 0);
427 if( (user->state == ps_connected_server) &&
428 (user->other->state == ps_connected_client) )
430 close(user->other->obj.fd);
431 user->other->obj.fd = -1;
432 user->other->state = ps_disconnected;
433 user->other->other = NULL;
437 user->state = ps_idle_server;
440 release_object(user);
443 DECL_HANDLER(get_named_pipe_info)
445 struct pipe_user *user;
447 user = get_pipe_user_obj(current->process, req->handle, 0);
451 req->flags = user->pipe->pipemode;
452 req->maxinstances = user->pipe->maxinstances;
453 req->insize = user->pipe->insize;
454 req->outsize = user->pipe->outsize;
456 release_object(user);