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
,
155 APC_ASYNC
,1,2,user
->overlapped
,status
);
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 return (struct fd
*)grab_object( user
->fd
);
169 static void pipe_user_destroy( struct object
*obj
)
171 struct pipe_user
*user
= (struct pipe_user
*)obj
;
173 assert( obj
->ops
== &pipe_user_ops
);
176 notify_waiter(user
,STATUS_HANDLES_CLOSED
);
180 release_object( user
->other
->fd
);
181 user
->other
->fd
= NULL
;
182 switch(user
->other
->state
)
184 case ps_connected_server
:
185 user
->other
->state
= ps_idle_server
;
187 case ps_connected_client
:
188 user
->other
->state
= ps_disconnected
;
191 fprintf(stderr
,"connected pipe has strange state %d!\n",
194 user
->other
->other
=NULL
;
198 /* remove user from pipe's user list */
199 if (user
->next
) user
->next
->prev
= user
->prev
;
200 if (user
->prev
) user
->prev
->next
= user
->next
;
201 else user
->pipe
->users
= user
->next
;
202 if (user
->thread
) release_object(user
->thread
);
203 release_object(user
->pipe
);
204 if (user
->fd
) release_object( user
->fd
);
207 static int pipe_user_get_poll_events( struct fd
*fd
)
209 return POLLIN
| POLLOUT
; /* FIXME */
212 static int pipe_user_get_info( struct fd
*fd
, struct get_file_info_reply
*reply
, int *flags
)
216 reply
->type
= FILE_TYPE_PIPE
;
218 reply
->access_time
= 0;
219 reply
->write_time
= 0;
220 reply
->size_high
= 0;
223 reply
->index_high
= 0;
224 reply
->index_low
= 0;
228 return FD_TYPE_DEFAULT
;
231 static struct named_pipe
*create_named_pipe( const WCHAR
*name
, size_t len
)
233 struct named_pipe
*pipe
;
235 if ((pipe
= create_named_object( sync_namespace
, &named_pipe_ops
, name
, len
)))
237 if (get_error() != STATUS_OBJECT_NAME_COLLISION
)
239 /* initialize it if it didn't already exist */
246 static struct named_pipe
*open_named_pipe( const WCHAR
*name
, size_t len
)
250 if ((obj
= find_object( sync_namespace
, name
, len
)))
252 if (obj
->ops
== &named_pipe_ops
) return (struct named_pipe
*)obj
;
253 release_object( obj
);
254 set_error( STATUS_OBJECT_TYPE_MISMATCH
);
256 else set_error( STATUS_OBJECT_NAME_NOT_FOUND
);
261 static struct pipe_user
*get_pipe_user_obj( struct process
*process
, obj_handle_t handle
,
262 unsigned int access
)
264 return (struct pipe_user
*)get_handle_obj( process
, handle
, access
, &pipe_user_ops
);
267 static struct pipe_user
*create_pipe_user( struct named_pipe
*pipe
)
269 struct pipe_user
*user
;
271 user
= alloc_object( &pipe_user_ops
);
277 user
->state
= ps_none
;
281 user
->overlapped
= NULL
;
283 /* add to list of pipe users */
284 if ((user
->next
= pipe
->users
)) user
->next
->prev
= user
;
293 static struct pipe_user
*find_partner(struct named_pipe
*pipe
, enum pipe_state state
)
297 for(x
= pipe
->users
; x
; x
=x
->next
)
306 return (struct pipe_user
*)grab_object( x
);
309 DECL_HANDLER(create_named_pipe
)
311 struct named_pipe
*pipe
;
312 struct pipe_user
*user
;
315 pipe
= create_named_pipe( get_req_data(), get_req_data_size() );
319 if (get_error() != STATUS_OBJECT_NAME_COLLISION
)
321 pipe
->insize
= req
->insize
;
322 pipe
->outsize
= req
->outsize
;
323 pipe
->maxinstances
= req
->maxinstances
;
324 pipe
->timeout
= req
->timeout
;
325 pipe
->pipemode
= req
->pipemode
;
328 user
= create_pipe_user( pipe
);
332 user
->state
= ps_idle_server
;
333 reply
->handle
= alloc_handle( current
->process
, user
, GENERIC_READ
|GENERIC_WRITE
, 0 );
334 release_object( user
);
337 release_object( pipe
);
340 DECL_HANDLER(open_named_pipe
)
342 struct pipe_user
*user
, *partner
;
343 struct named_pipe
*pipe
;
347 if (!(pipe
= open_named_pipe( get_req_data(), get_req_data_size() )))
349 set_error( STATUS_NO_SUCH_FILE
);
352 if (!(partner
= find_partner(pipe
, ps_wait_open
)))
354 release_object(pipe
);
355 set_error( STATUS_PIPE_NOT_AVAILABLE
);
358 if ((user
= create_pipe_user( pipe
)))
362 if(!socketpair(PF_UNIX
, SOCK_STREAM
, 0, fds
))
364 user
->fd
= create_anonymous_fd( &pipe_user_fd_ops
, fds
[1], &user
->obj
);
365 partner
->fd
= create_anonymous_fd( &pipe_user_fd_ops
, fds
[0], &partner
->obj
);
366 if (user
->fd
&& partner
->fd
)
368 notify_waiter(partner
,STATUS_SUCCESS
);
369 partner
->state
= ps_connected_server
;
370 partner
->other
= user
;
371 user
->state
= ps_connected_client
;
372 user
->other
= partner
;
373 reply
->handle
= alloc_handle( current
->process
, user
, req
->access
, 0 );
376 else file_set_error();
378 release_object( user
);
380 release_object( partner
);
381 release_object( pipe
);
384 DECL_HANDLER(connect_named_pipe
)
386 struct pipe_user
*user
, *partner
;
388 user
= get_pipe_user_obj(current
->process
, req
->handle
, 0);
392 if( user
->state
!= ps_idle_server
)
394 set_error(STATUS_PORT_ALREADY_SET
);
398 user
->state
= ps_wait_open
;
399 user
->thread
= (struct thread
*)grab_object(current
);
400 user
->func
= req
->func
;
401 user
->overlapped
= req
->overlapped
;
403 /* notify all waiters that a pipe just became available */
404 while( (partner
= find_partner(user
->pipe
,ps_wait_connect
)) )
406 notify_waiter(partner
,STATUS_SUCCESS
);
407 release_object(partner
);
411 release_object(user
);
414 DECL_HANDLER(wait_named_pipe
)
416 struct named_pipe
*pipe
;
417 struct pipe_user
*partner
;
419 if (!(pipe
= open_named_pipe( get_req_data(), get_req_data_size() )))
421 set_error( STATUS_PIPE_NOT_AVAILABLE
);
424 if( (partner
= find_partner(pipe
,ps_wait_open
)) )
426 /* this should use notify_waiter,
427 but no pipe_user object exists now... */
428 thread_queue_apc(current
,NULL
,req
->func
,
429 APC_ASYNC
,1,2,req
->overlapped
,STATUS_SUCCESS
);
430 release_object(partner
);
434 struct pipe_user
*user
;
436 if( (user
= create_pipe_user( pipe
)) )
438 user
->state
= ps_wait_connect
;
439 user
->thread
= (struct thread
*)grab_object(current
);
440 user
->func
= req
->func
;
441 user
->overlapped
= req
->overlapped
;
442 /* don't release it */
445 release_object(pipe
);
448 DECL_HANDLER(disconnect_named_pipe
)
450 struct pipe_user
*user
;
452 user
= get_pipe_user_obj(current
->process
, req
->handle
, 0);
455 if( (user
->state
== ps_connected_server
) &&
456 (user
->other
->state
== ps_connected_client
) )
458 release_object( user
->other
->fd
);
459 user
->other
->fd
= NULL
;
460 user
->other
->state
= ps_disconnected
;
461 user
->other
->other
= NULL
;
463 release_object( user
->fd
);
465 user
->state
= ps_idle_server
;
468 release_object(user
);
471 DECL_HANDLER(get_named_pipe_info
)
473 struct pipe_user
*user
;
475 user
= get_pipe_user_obj(current
->process
, req
->handle
, 0);
479 reply
->flags
= user
->pipe
->pipemode
;
480 reply
->maxinstances
= user
->pipe
->maxinstances
;
481 reply
->insize
= user
->pipe
->insize
;
482 reply
->outsize
= user
->pipe
->outsize
;
484 release_object(user
);