2 * Server-side pipe management
4 * Copyright (C) 1998 Alexandre Julliard
5 * Copyright (C) 2001 Mike McCormack
7 * 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.
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.
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
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * improve error handling
26 #include "wine/port.h"
34 #include <sys/types.h>
35 #ifdef HAVE_SYS_SOCKET_H
36 #include <sys/socket.h>
65 enum pipe_state state;
66 struct pipe_user *other;
67 struct named_pipe *pipe;
68 struct pipe_user *next;
69 struct pipe_user *prev;
70 struct thread *thread;
77 struct object obj; /* object header */
78 unsigned int pipemode;
79 unsigned int maxinstances;
83 struct pipe_user *users;
86 static void named_pipe_dump( struct object *obj, int verbose );
87 static void named_pipe_destroy( struct object *obj);
89 static const struct object_ops named_pipe_ops =
91 sizeof(struct named_pipe), /* size */
92 named_pipe_dump, /* dump */
93 no_add_queue, /* add_queue */
94 NULL, /* remove_queue */
97 no_get_fd, /* get_fd */
98 named_pipe_destroy /* destroy */
101 static void pipe_user_dump( struct object *obj, int verbose );
102 static struct fd *pipe_user_get_fd( struct object *obj );
103 static void pipe_user_destroy( struct object *obj);
105 static int pipe_user_get_poll_events( struct fd *fd );
106 static int pipe_user_get_info( struct fd *fd, struct get_file_info_reply *reply, int *flags );
108 static const struct object_ops pipe_user_ops =
110 sizeof(struct pipe_user), /* size */
111 pipe_user_dump, /* dump */
112 default_fd_add_queue, /* add_queue */
113 default_fd_remove_queue, /* remove_queue */
114 default_fd_signaled, /* signaled */
115 no_satisfied, /* satisfied */
116 pipe_user_get_fd, /* get_fd */
117 pipe_user_destroy /* destroy */
120 static const struct fd_ops pipe_user_fd_ops =
122 pipe_user_get_poll_events, /* get_poll_events */
123 default_poll_event, /* poll_event */
124 no_flush, /* flush */
125 pipe_user_get_info, /* get_file_info */
126 no_queue_async /* queue_async */
129 static void named_pipe_dump( struct object *obj, int verbose )
131 struct named_pipe *pipe = (struct named_pipe *)obj;
132 assert( obj->ops == &named_pipe_ops );
133 fprintf( stderr, "named pipe %p\n" ,pipe);
136 static void pipe_user_dump( struct object *obj, int verbose )
138 struct pipe_user *user = (struct pipe_user *)obj;
139 assert( obj->ops == &pipe_user_ops );
140 fprintf( stderr, "named pipe user %p (state %d)\n", user, user->state );
143 static void named_pipe_destroy( struct object *obj)
145 struct named_pipe *pipe = (struct named_pipe *)obj;
146 assert( !pipe->users );
149 static void notify_waiter( struct pipe_user *user, unsigned int status)
151 if(user->thread && user->func && user->overlapped)
153 /* queue a system APC, to notify a waiting thread */
154 thread_queue_apc(user->thread, NULL, user->func, APC_ASYNC, 1,
155 user->overlapped, (void *)status, NULL);
157 if (user->thread) release_object(user->thread);
160 user->overlapped=NULL;
163 static struct fd *pipe_user_get_fd( struct object *obj )
165 struct pipe_user *user = (struct pipe_user *)obj;
166 if (user->fd) return (struct fd *)grab_object( user->fd );
167 set_error( STATUS_PIPE_DISCONNECTED );
171 static void pipe_user_destroy( struct object *obj)
173 struct pipe_user *user = (struct pipe_user *)obj;
175 assert( obj->ops == &pipe_user_ops );
178 notify_waiter(user,STATUS_HANDLES_CLOSED);
182 release_object( user->other->fd );
183 user->other->fd = NULL;
184 switch(user->other->state)
186 case ps_connected_server:
187 user->other->state = ps_idle_server;
189 case ps_connected_client:
190 user->other->state = ps_disconnected;
193 fprintf(stderr,"connected pipe has strange state %d!\n",
196 user->other->other=NULL;
200 /* remove user from pipe's user list */
201 if (user->next) user->next->prev = user->prev;
202 if (user->prev) user->prev->next = user->next;
203 else user->pipe->users = user->next;
204 if (user->thread) release_object(user->thread);
205 release_object(user->pipe);
206 if (user->fd) release_object( user->fd );
209 static int pipe_user_get_poll_events( struct fd *fd )
211 return POLLIN | POLLOUT; /* FIXME */
214 static int pipe_user_get_info( struct fd *fd, struct get_file_info_reply *reply, int *flags )
218 reply->type = FILE_TYPE_PIPE;
220 reply->access_time = 0;
221 reply->write_time = 0;
222 reply->size_high = 0;
225 reply->index_high = 0;
226 reply->index_low = 0;
230 return FD_TYPE_DEFAULT;
233 static struct named_pipe *create_named_pipe( const WCHAR *name, size_t len )
235 struct named_pipe *pipe;
237 if ((pipe = create_named_object( sync_namespace, &named_pipe_ops, name, len )))
239 if (get_error() != STATUS_OBJECT_NAME_COLLISION)
241 /* initialize it if it didn't already exist */
248 static struct named_pipe *open_named_pipe( const WCHAR *name, size_t len )
252 if ((obj = find_object( sync_namespace, name, len )))
254 if (obj->ops == &named_pipe_ops) return (struct named_pipe *)obj;
255 release_object( obj );
256 set_error( STATUS_OBJECT_TYPE_MISMATCH );
258 else set_error( STATUS_OBJECT_NAME_NOT_FOUND );
263 static struct pipe_user *get_pipe_user_obj( struct process *process, obj_handle_t handle,
264 unsigned int access )
266 return (struct pipe_user *)get_handle_obj( process, handle, access, &pipe_user_ops );
269 static struct pipe_user *create_pipe_user( struct named_pipe *pipe )
271 struct pipe_user *user;
273 user = alloc_object( &pipe_user_ops );
279 user->state = ps_none;
283 user->overlapped = NULL;
285 /* add to list of pipe users */
286 if ((user->next = pipe->users)) user->next->prev = user;
295 static struct pipe_user *find_partner(struct named_pipe *pipe, enum pipe_state state)
299 for(x = pipe->users; x; x=x->next)
308 return (struct pipe_user *)grab_object( x );
311 DECL_HANDLER(create_named_pipe)
313 struct named_pipe *pipe;
314 struct pipe_user *user;
317 pipe = create_named_pipe( get_req_data(), get_req_data_size() );
321 if (get_error() != STATUS_OBJECT_NAME_COLLISION)
323 pipe->insize = req->insize;
324 pipe->outsize = req->outsize;
325 pipe->maxinstances = req->maxinstances;
326 pipe->timeout = req->timeout;
327 pipe->pipemode = req->pipemode;
330 user = create_pipe_user( pipe );
334 user->state = ps_idle_server;
335 reply->handle = alloc_handle( current->process, user, GENERIC_READ|GENERIC_WRITE, 0 );
336 release_object( user );
339 release_object( pipe );
342 DECL_HANDLER(open_named_pipe)
344 struct pipe_user *user, *partner;
345 struct named_pipe *pipe;
349 if (!(pipe = open_named_pipe( get_req_data(), get_req_data_size() )))
351 set_error( STATUS_NO_SUCH_FILE );
354 if (!(partner = find_partner(pipe, ps_wait_open)))
356 release_object(pipe);
357 set_error( STATUS_PIPE_NOT_AVAILABLE );
360 if ((user = create_pipe_user( pipe )))
364 if(!socketpair(PF_UNIX, SOCK_STREAM, 0, fds))
366 user->fd = create_anonymous_fd( &pipe_user_fd_ops, fds[1], &user->obj );
367 partner->fd = create_anonymous_fd( &pipe_user_fd_ops, fds[0], &partner->obj );
368 if (user->fd && partner->fd)
370 notify_waiter(partner,STATUS_SUCCESS);
371 partner->state = ps_connected_server;
372 partner->other = user;
373 user->state = ps_connected_client;
374 user->other = partner;
375 reply->handle = alloc_handle( current->process, user, req->access, 0 );
378 else file_set_error();
380 release_object( user );
382 release_object( partner );
383 release_object( pipe );
386 DECL_HANDLER(connect_named_pipe)
388 struct pipe_user *user, *partner;
390 user = get_pipe_user_obj(current->process, req->handle, 0);
394 if( user->state != ps_idle_server )
396 set_error(STATUS_PORT_ALREADY_SET);
400 user->state = ps_wait_open;
401 user->thread = (struct thread *)grab_object(current);
402 user->func = req->func;
403 user->overlapped = req->overlapped;
405 /* notify all waiters that a pipe just became available */
406 while( (partner = find_partner(user->pipe,ps_wait_connect)) )
408 notify_waiter(partner,STATUS_SUCCESS);
409 release_object(partner);
413 release_object(user);
416 DECL_HANDLER(wait_named_pipe)
418 struct named_pipe *pipe;
419 struct pipe_user *partner;
421 if (!(pipe = open_named_pipe( get_req_data(), get_req_data_size() )))
423 set_error( STATUS_PIPE_NOT_AVAILABLE );
426 if( (partner = find_partner(pipe,ps_wait_open)) )
428 /* this should use notify_waiter,
429 but no pipe_user object exists now... */
430 thread_queue_apc(current,NULL,req->func,
431 APC_ASYNC, 1, req->overlapped, STATUS_SUCCESS, NULL);
432 release_object(partner);
436 struct pipe_user *user;
438 if( (user = create_pipe_user( pipe )) )
440 user->state = ps_wait_connect;
441 user->thread = (struct thread *)grab_object(current);
442 user->func = req->func;
443 user->overlapped = req->overlapped;
444 /* don't release it */
447 release_object(pipe);
450 DECL_HANDLER(disconnect_named_pipe)
452 struct pipe_user *user;
454 user = get_pipe_user_obj(current->process, req->handle, 0);
457 if( (user->state == ps_connected_server) &&
458 (user->other->state == ps_connected_client) )
460 release_object( user->other->fd );
461 user->other->fd = NULL;
462 user->other->state = ps_disconnected;
463 user->other->other = NULL;
465 release_object( user->fd );
467 user->state = ps_idle_server;
470 release_object(user);
473 DECL_HANDLER(get_named_pipe_info)
475 struct pipe_user *user;
477 user = get_pipe_user_obj(current->process, req->handle, 0);
481 reply->flags = user->pipe->pipemode;
482 reply->maxinstances = user->pipe->maxinstances;
483 reply->insize = user->pipe->insize;
484 reply->outsize = user->pipe->outsize;
486 release_object(user);