Updated regression testing documentation.
[wine/testsucceed.git] / server / named_pipe.c
blob29c761437715ae510b9f634c410570f968bfe929
1 /*
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
21 * TODO:
22 * improve error handling
25 #include "config.h"
26 #include "wine/port.h"
28 #include <assert.h>
29 #include <fcntl.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <sys/time.h>
34 #include <sys/types.h>
35 #ifdef HAVE_SYS_SOCKET_H
36 #include <sys/socket.h>
37 #endif
38 #include <time.h>
39 #include <unistd.h>
41 #include "winbase.h"
43 #include "file.h"
44 #include "handle.h"
45 #include "thread.h"
46 #include "request.h"
48 enum pipe_state
50 ps_none,
51 ps_idle_server,
52 ps_wait_open,
53 ps_wait_connect,
54 ps_connected_server,
55 ps_connected_client,
56 ps_disconnected
59 struct named_pipe;
61 struct pipe_user
63 struct object obj;
64 enum pipe_state state;
65 struct pipe_user *other;
66 struct named_pipe *pipe;
67 struct pipe_user *next;
68 struct pipe_user *prev;
69 struct thread *thread;
70 void *func;
71 void *overlapped;
74 struct named_pipe
76 struct object obj; /* object header */
77 unsigned int pipemode;
78 unsigned int maxinstances;
79 unsigned int outsize;
80 unsigned int insize;
81 unsigned int timeout;
82 struct pipe_user *users;
85 static void named_pipe_dump( struct object *obj, int verbose );
86 static void named_pipe_destroy( struct object *obj);
88 static const struct object_ops named_pipe_ops =
90 sizeof(struct named_pipe), /* size */
91 named_pipe_dump, /* dump */
92 no_add_queue, /* add_queue */
93 NULL, /* remove_queue */
94 NULL, /* signaled */
95 NULL, /* satisfied */
96 no_get_fd, /* get_fd */
97 named_pipe_destroy /* destroy */
100 static void pipe_user_dump( struct object *obj, int verbose );
101 static void pipe_user_destroy( struct object *obj);
102 static int pipe_user_get_info( struct fd *fd, struct get_file_info_reply *reply, int *flags );
104 static const struct object_ops pipe_user_ops =
106 sizeof(struct pipe_user), /* size */
107 pipe_user_dump, /* dump */
108 default_fd_add_queue, /* add_queue */
109 default_fd_remove_queue, /* remove_queue */
110 default_fd_signaled, /* signaled */
111 no_satisfied, /* satisfied */
112 default_get_fd, /* get_fd */
113 pipe_user_destroy /* destroy */
116 static const struct fd_ops pipe_user_fd_ops =
118 NULL, /* get_poll_events */
119 default_poll_event, /* poll_event */
120 no_flush, /* flush */
121 pipe_user_get_info, /* get_file_info */
122 no_queue_async /* queue_async */
125 static void named_pipe_dump( struct object *obj, int verbose )
127 struct named_pipe *pipe = (struct named_pipe *)obj;
128 assert( obj->ops == &named_pipe_ops );
129 fprintf( stderr, "named pipe %p\n" ,pipe);
132 static void pipe_user_dump( struct object *obj, int verbose )
134 struct pipe_user *user = (struct pipe_user *)obj;
135 assert( obj->ops == &pipe_user_ops );
136 fprintf( stderr, "named pipe user %p (state %d)\n", user, user->state );
139 static void named_pipe_destroy( struct object *obj)
141 struct named_pipe *pipe = (struct named_pipe *)obj;
142 assert( !pipe->users );
145 static void notify_waiter( struct pipe_user *user, unsigned int status)
147 if(user->thread && user->func && user->overlapped)
149 /* queue a system APC, to notify a waiting thread */
150 thread_queue_apc(user->thread,NULL,user->func,
151 APC_ASYNC,1,2,user->overlapped,status);
153 if (user->thread) release_object(user->thread);
154 user->thread = NULL;
155 user->func = NULL;
156 user->overlapped=NULL;
159 static void pipe_user_destroy( struct object *obj)
161 struct pipe_user *user = (struct pipe_user *)obj;
163 assert( obj->ops == &pipe_user_ops );
165 if(user->overlapped)
166 notify_waiter(user,STATUS_HANDLES_CLOSED);
168 if(user->other)
170 release_object( user->other->obj.fd_obj );
171 user->other->obj.fd_obj = NULL;
172 switch(user->other->state)
174 case ps_connected_server:
175 user->other->state = ps_idle_server;
176 break;
177 case ps_connected_client:
178 user->other->state = ps_disconnected;
179 break;
180 default:
181 fprintf(stderr,"connected pipe has strange state %d!\n",
182 user->other->state);
184 user->other->other=NULL;
185 user->other = NULL;
188 /* remove user from pipe's user list */
189 if (user->next) user->next->prev = user->prev;
190 if (user->prev) user->prev->next = user->next;
191 else user->pipe->users = user->next;
192 if (user->thread) release_object(user->thread);
193 release_object(user->pipe);
196 static int pipe_user_get_info( struct fd *fd, struct get_file_info_reply *reply, int *flags )
198 if (reply)
200 reply->type = FILE_TYPE_PIPE;
201 reply->attr = 0;
202 reply->access_time = 0;
203 reply->write_time = 0;
204 reply->size_high = 0;
205 reply->size_low = 0;
206 reply->links = 0;
207 reply->index_high = 0;
208 reply->index_low = 0;
209 reply->serial = 0;
211 *flags = 0;
212 return FD_TYPE_DEFAULT;
215 static struct named_pipe *create_named_pipe( const WCHAR *name, size_t len )
217 struct named_pipe *pipe;
219 if ((pipe = create_named_object( sync_namespace, &named_pipe_ops, name, len )))
221 if (get_error() != STATUS_OBJECT_NAME_COLLISION)
223 /* initialize it if it didn't already exist */
224 pipe->users = 0;
227 return pipe;
230 static struct pipe_user *get_pipe_user_obj( struct process *process, obj_handle_t handle,
231 unsigned int access )
233 return (struct pipe_user *)get_handle_obj( process, handle, access, &pipe_user_ops );
236 static struct pipe_user *create_pipe_user( struct named_pipe *pipe, int fd )
238 struct pipe_user *user;
240 user = alloc_fd_object( &pipe_user_ops, &pipe_user_fd_ops, fd );
241 if(!user)
242 return NULL;
244 user->pipe = pipe;
245 user->state = ps_none;
246 user->other = NULL;
247 user->thread = NULL;
248 user->func = NULL;
249 user->overlapped = NULL;
251 /* add to list of pipe users */
252 if ((user->next = pipe->users)) user->next->prev = user;
253 user->prev = NULL;
254 pipe->users = user;
256 grab_object(pipe);
258 return user;
261 static struct pipe_user *find_partner(struct named_pipe *pipe, enum pipe_state state)
263 struct pipe_user *x;
265 for(x = pipe->users; x; x=x->next)
267 if(x->state==state)
268 break;
271 if(!x)
272 return NULL;
274 return (struct pipe_user *)grab_object( x );
277 DECL_HANDLER(create_named_pipe)
279 struct named_pipe *pipe;
280 struct pipe_user *user;
282 reply->handle = 0;
283 pipe = create_named_pipe( get_req_data(), get_req_data_size() );
284 if(!pipe)
285 return;
287 if (get_error() != STATUS_OBJECT_NAME_COLLISION)
289 pipe->insize = req->insize;
290 pipe->outsize = req->outsize;
291 pipe->maxinstances = req->maxinstances;
292 pipe->timeout = req->timeout;
293 pipe->pipemode = req->pipemode;
296 user = create_pipe_user (pipe, -1);
298 if(user)
300 user->state = ps_idle_server;
301 reply->handle = alloc_handle( current->process, user, GENERIC_READ|GENERIC_WRITE, 0 );
302 release_object( user );
305 release_object( pipe );
308 DECL_HANDLER(open_named_pipe)
310 struct named_pipe *pipe;
312 reply->handle = 0;
313 pipe = create_named_pipe( get_req_data(), get_req_data_size() );
314 if(!pipe)
315 return;
317 if (get_error() == STATUS_OBJECT_NAME_COLLISION)
319 struct pipe_user *partner;
321 if ((partner = find_partner(pipe, ps_wait_open)))
323 int fds[2];
325 if(!socketpair(PF_UNIX, SOCK_STREAM, 0, fds))
327 struct pipe_user *user;
329 if( (user = create_pipe_user (pipe, fds[1])) )
331 set_unix_fd( &partner->obj, fds[0] );
332 notify_waiter(partner,STATUS_SUCCESS);
333 partner->state = ps_connected_server;
334 partner->other = user;
335 user->state = ps_connected_client;
336 user->other = partner;
337 reply->handle = alloc_handle( current->process, user, req->access, 0 );
338 release_object(user);
340 else
342 close(fds[0]);
345 release_object( partner );
347 else
349 set_error(STATUS_PIPE_NOT_AVAILABLE);
352 else
354 set_error(STATUS_NO_SUCH_FILE);
357 release_object(pipe);
360 DECL_HANDLER(connect_named_pipe)
362 struct pipe_user *user, *partner;
364 user = get_pipe_user_obj(current->process, req->handle, 0);
365 if(!user)
366 return;
368 if( user->state != ps_idle_server )
370 set_error(STATUS_PORT_ALREADY_SET);
372 else
374 user->state = ps_wait_open;
375 user->thread = (struct thread *)grab_object(current);
376 user->func = req->func;
377 user->overlapped = req->overlapped;
379 /* notify all waiters that a pipe just became available */
380 while( (partner = find_partner(user->pipe,ps_wait_connect)) )
382 notify_waiter(partner,STATUS_SUCCESS);
383 release_object(partner);
384 release_object(partner);
388 release_object(user);
391 DECL_HANDLER(wait_named_pipe)
393 struct named_pipe *pipe;
395 pipe = create_named_pipe( get_req_data(), get_req_data_size() );
396 if( pipe )
398 /* only wait if the pipe already exists */
399 if(get_error() == STATUS_OBJECT_NAME_COLLISION)
401 struct pipe_user *partner;
403 set_error(STATUS_SUCCESS);
404 if( (partner = find_partner(pipe,ps_wait_open)) )
406 /* this should use notify_waiter,
407 but no pipe_user object exists now... */
408 thread_queue_apc(current,NULL,req->func,
409 APC_ASYNC,1,2,req->overlapped,STATUS_SUCCESS);
410 release_object(partner);
412 else
414 struct pipe_user *user;
416 if( (user = create_pipe_user (pipe, -1)) )
418 user->state = ps_wait_connect;
419 user->thread = (struct thread *)grab_object(current);
420 user->func = req->func;
421 user->overlapped = req->overlapped;
422 /* don't release it */
426 else
428 set_error(STATUS_PIPE_NOT_AVAILABLE);
430 release_object(pipe);
434 DECL_HANDLER(disconnect_named_pipe)
436 struct pipe_user *user;
438 user = get_pipe_user_obj(current->process, req->handle, 0);
439 if(!user)
440 return;
441 if( (user->state == ps_connected_server) &&
442 (user->other->state == ps_connected_client) )
444 release_object( user->other->obj.fd_obj );
445 user->other->obj.fd_obj = NULL;
446 user->other->state = ps_disconnected;
447 user->other->other = NULL;
449 release_object( user->obj.fd_obj );
450 user->obj.fd_obj = NULL;
451 user->state = ps_idle_server;
452 user->other = NULL;
454 release_object(user);
457 DECL_HANDLER(get_named_pipe_info)
459 struct pipe_user *user;
461 user = get_pipe_user_obj(current->process, req->handle, 0);
462 if(!user)
463 return;
465 reply->flags = user->pipe->pipemode;
466 reply->maxinstances = user->pipe->maxinstances;
467 reply->insize = user->pipe->insize;
468 reply->outsize = user->pipe->outsize;
470 release_object(user);