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
33 #include <sys/types.h>
34 #include <sys/socket.h>
60 enum pipe_state state
;
61 struct pipe_user
*other
;
62 struct named_pipe
*pipe
;
63 struct pipe_user
*next
;
64 struct pipe_user
*prev
;
65 struct thread
*thread
;
72 struct object obj
; /* object header */
73 unsigned int pipemode
;
74 unsigned int maxinstances
;
78 struct pipe_user
*users
;
81 static void named_pipe_dump( struct object
*obj
, int verbose
);
82 static void named_pipe_destroy( struct object
*obj
);
84 static const struct object_ops named_pipe_ops
=
86 sizeof(struct named_pipe
), /* size */
87 named_pipe_dump
, /* dump */
88 no_add_queue
, /* add_queue */
89 NULL
, /* remove_queue */
92 NULL
, /* get_poll_events */
93 NULL
, /* poll_event */
94 no_get_fd
, /* get_fd */
96 no_get_file_info
, /* get_file_info */
97 NULL
, /* queue_async */
98 named_pipe_destroy
/* destroy */
101 static void pipe_user_dump( struct object
*obj
, int verbose
);
102 static void pipe_user_destroy( struct object
*obj
);
103 static int pipe_user_get_fd( struct object
*obj
);
104 static int pipe_user_get_info( struct object
*obj
, struct get_file_info_reply
*reply
, int *flags
);
106 static const struct object_ops pipe_user_ops
=
108 sizeof(struct pipe_user
), /* size */
109 pipe_user_dump
, /* dump */
110 default_poll_add_queue
, /* add_queue */
111 default_poll_remove_queue
, /* remove_queue */
112 default_poll_signaled
, /* signaled */
113 no_satisfied
, /* satisfied */
114 NULL
, /* get_poll_events */
115 default_poll_event
, /* poll_event */
116 pipe_user_get_fd
, /* get_fd */
117 no_flush
, /* flush */
118 pipe_user_get_info
, /* get_file_info */
119 NULL
, /* queue_async */
120 pipe_user_destroy
/* destroy */
123 static void named_pipe_dump( struct object
*obj
, int verbose
)
125 struct named_pipe
*pipe
= (struct named_pipe
*)obj
;
126 assert( obj
->ops
== &named_pipe_ops
);
127 fprintf( stderr
, "named pipe %p\n" ,pipe
);
130 static void pipe_user_dump( struct object
*obj
, int verbose
)
132 struct pipe_user
*user
= (struct pipe_user
*)obj
;
133 assert( obj
->ops
== &pipe_user_ops
);
134 fprintf( stderr
, "named pipe user %p (state %d)\n", user
, user
->state
);
137 static void named_pipe_destroy( struct object
*obj
)
139 struct named_pipe
*pipe
= (struct named_pipe
*)obj
;
140 assert( !pipe
->users
);
143 static void notify_waiter( struct pipe_user
*user
, unsigned int status
)
145 if(user
->thread
&& user
->func
&& user
->overlapped
)
147 /* queue a system APC, to notify a waiting thread */
148 thread_queue_apc(user
->thread
,NULL
,user
->func
,
149 APC_ASYNC
,1,2,user
->overlapped
,status
);
151 if (user
->thread
) release_object(user
->thread
);
154 user
->overlapped
=NULL
;
157 static void pipe_user_destroy( struct object
*obj
)
159 struct pipe_user
*user
= (struct pipe_user
*)obj
;
161 assert( obj
->ops
== &pipe_user_ops
);
164 notify_waiter(user
,STATUS_HANDLES_CLOSED
);
168 close(user
->other
->obj
.fd
);
169 user
->other
->obj
.fd
= -1;
170 switch(user
->other
->state
)
172 case ps_connected_server
:
173 user
->other
->state
= ps_idle_server
;
175 case ps_connected_client
:
176 user
->other
->state
= ps_disconnected
;
179 fprintf(stderr
,"connected pipe has strange state %d!\n",
182 user
->other
->other
=NULL
;
186 /* remove user from pipe's user list */
187 if (user
->next
) user
->next
->prev
= user
->prev
;
188 if (user
->prev
) user
->prev
->next
= user
->next
;
189 else user
->pipe
->users
= user
->next
;
190 if (user
->thread
) release_object(user
->thread
);
191 release_object(user
->pipe
);
194 static int pipe_user_get_fd( struct object
*obj
)
196 struct pipe_user
*user
= (struct pipe_user
*)obj
;
197 assert( obj
->ops
== &pipe_user_ops
);
201 static int pipe_user_get_info( struct object
*obj
, struct get_file_info_reply
*reply
, int *flags
)
205 reply
->type
= FILE_TYPE_PIPE
;
207 reply
->access_time
= 0;
208 reply
->write_time
= 0;
209 reply
->size_high
= 0;
212 reply
->index_high
= 0;
213 reply
->index_low
= 0;
217 return FD_TYPE_DEFAULT
;
220 static struct named_pipe
*create_named_pipe( const WCHAR
*name
, size_t len
)
222 struct named_pipe
*pipe
;
224 if ((pipe
= create_named_object( &named_pipe_ops
, name
, len
)))
226 if (get_error() != STATUS_OBJECT_NAME_COLLISION
)
228 /* initialize it if it didn't already exist */
235 static struct pipe_user
*get_pipe_user_obj( struct process
*process
, handle_t handle
,
236 unsigned int access
)
238 return (struct pipe_user
*)get_handle_obj( process
, handle
, access
, &pipe_user_ops
);
241 static struct pipe_user
*create_pipe_user( struct named_pipe
*pipe
, int fd
)
243 struct pipe_user
*user
;
245 user
= alloc_object( &pipe_user_ops
, fd
);
250 user
->state
= ps_none
;
254 user
->overlapped
= NULL
;
256 /* add to list of pipe users */
257 if ((user
->next
= pipe
->users
)) user
->next
->prev
= user
;
266 static struct pipe_user
*find_partner(struct named_pipe
*pipe
, enum pipe_state state
)
270 for(x
= pipe
->users
; x
; x
=x
->next
)
279 return (struct pipe_user
*)grab_object( x
);
282 DECL_HANDLER(create_named_pipe
)
284 struct named_pipe
*pipe
;
285 struct pipe_user
*user
;
288 pipe
= create_named_pipe( get_req_data(), get_req_data_size() );
292 if (get_error() != STATUS_OBJECT_NAME_COLLISION
)
294 pipe
->insize
= req
->insize
;
295 pipe
->outsize
= req
->outsize
;
296 pipe
->maxinstances
= req
->maxinstances
;
297 pipe
->timeout
= req
->timeout
;
298 pipe
->pipemode
= req
->pipemode
;
301 user
= create_pipe_user (pipe
, -1);
305 user
->state
= ps_idle_server
;
306 reply
->handle
= alloc_handle( current
->process
, user
, GENERIC_READ
|GENERIC_WRITE
, 0 );
307 release_object( user
);
310 release_object( pipe
);
313 DECL_HANDLER(open_named_pipe
)
315 struct named_pipe
*pipe
;
318 pipe
= create_named_pipe( get_req_data(), get_req_data_size() );
322 if (get_error() == STATUS_OBJECT_NAME_COLLISION
)
324 struct pipe_user
*partner
;
326 if ((partner
= find_partner(pipe
, ps_wait_open
)))
330 if(!socketpair(PF_UNIX
, SOCK_STREAM
, 0, fds
))
332 struct pipe_user
*user
;
334 if( (user
= create_pipe_user (pipe
, fds
[1])) )
336 partner
->obj
.fd
= fds
[0];
337 notify_waiter(partner
,STATUS_SUCCESS
);
338 partner
->state
= ps_connected_server
;
339 partner
->other
= user
;
340 user
->state
= ps_connected_client
;
341 user
->other
= partner
;
342 reply
->handle
= alloc_handle( current
->process
, user
, req
->access
, 0 );
343 release_object(user
);
350 release_object( partner
);
354 set_error(STATUS_PIPE_NOT_AVAILABLE
);
359 set_error(STATUS_NO_SUCH_FILE
);
362 release_object(pipe
);
365 DECL_HANDLER(connect_named_pipe
)
367 struct pipe_user
*user
, *partner
;
369 user
= get_pipe_user_obj(current
->process
, req
->handle
, 0);
373 if( user
->state
!= ps_idle_server
)
375 set_error(STATUS_PORT_ALREADY_SET
);
379 user
->state
= ps_wait_open
;
380 user
->thread
= (struct thread
*)grab_object(current
);
381 user
->func
= req
->func
;
382 user
->overlapped
= req
->overlapped
;
384 /* notify all waiters that a pipe just became available */
385 while( (partner
= find_partner(user
->pipe
,ps_wait_connect
)) )
387 notify_waiter(partner
,STATUS_SUCCESS
);
388 release_object(partner
);
389 release_object(partner
);
393 release_object(user
);
396 DECL_HANDLER(wait_named_pipe
)
398 struct named_pipe
*pipe
;
400 pipe
= create_named_pipe( get_req_data(), get_req_data_size() );
403 /* only wait if the pipe already exists */
404 if(get_error() == STATUS_OBJECT_NAME_COLLISION
)
406 struct pipe_user
*partner
;
408 set_error(STATUS_SUCCESS
);
409 if( (partner
= find_partner(pipe
,ps_wait_open
)) )
411 /* this should use notify_waiter,
412 but no pipe_user object exists now... */
413 thread_queue_apc(current
,NULL
,req
->func
,
414 APC_ASYNC
,1,2,req
->overlapped
,STATUS_SUCCESS
);
415 release_object(partner
);
419 struct pipe_user
*user
;
421 if( (user
= create_pipe_user (pipe
, -1)) )
423 user
->state
= ps_wait_connect
;
424 user
->thread
= (struct thread
*)grab_object(current
);
425 user
->func
= req
->func
;
426 user
->overlapped
= req
->overlapped
;
427 /* don't release it */
433 set_error(STATUS_PIPE_NOT_AVAILABLE
);
435 release_object(pipe
);
439 DECL_HANDLER(disconnect_named_pipe
)
441 struct pipe_user
*user
;
443 user
= get_pipe_user_obj(current
->process
, req
->handle
, 0);
446 if( (user
->state
== ps_connected_server
) &&
447 (user
->other
->state
== ps_connected_client
) )
449 close(user
->other
->obj
.fd
);
450 user
->other
->obj
.fd
= -1;
451 user
->other
->state
= ps_disconnected
;
452 user
->other
->other
= NULL
;
456 user
->state
= ps_idle_server
;
459 release_object(user
);
462 DECL_HANDLER(get_named_pipe_info
)
464 struct pipe_user
*user
;
466 user
= get_pipe_user_obj(current
->process
, req
->handle
, 0);
470 reply
->flags
= user
->pipe
->pipemode
;
471 reply
->maxinstances
= user
->pipe
->maxinstances
;
472 reply
->insize
= user
->pipe
->insize
;
473 reply
->outsize
= user
->pipe
->outsize
;
475 release_object(user
);