blob: ecad8c149b1305cb26dd2ed380acb3b60698882d [file] [log] [blame]
Mike McCormackde7c3002001-07-10 19:16:49 +00001/*
2 * Server-side pipe management
3 *
4 * Copyright (C) 1998 Alexandre Julliard
Mike McCormackbf554572001-08-23 23:29:20 +00005 * Copyright (C) 2001 Mike McCormack
6 *
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00007 * 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.
11 *
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.
16 *
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
20 *
Mike McCormackbf554572001-08-23 23:29:20 +000021 * TODO:
22 * improve error handling
Mike McCormackde7c3002001-07-10 19:16:49 +000023 */
24
25#include "config.h"
Alexandre Julliard5769d1d2002-04-26 19:05:15 +000026#include "wine/port.h"
Mike McCormackde7c3002001-07-10 19:16:49 +000027
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#include <sys/socket.h>
36#include <time.h>
37#include <unistd.h>
38
39#include "winbase.h"
40
41#include "handle.h"
42#include "thread.h"
43#include "request.h"
44
Mike McCormackbf554572001-08-23 23:29:20 +000045enum pipe_state
46{
47 ps_none,
48 ps_idle_server,
49 ps_wait_open,
50 ps_wait_connect,
51 ps_connected_server,
52 ps_connected_client,
53 ps_disconnected
54};
55
Mike McCormackde7c3002001-07-10 19:16:49 +000056struct named_pipe;
57
58struct pipe_user
59{
60 struct object obj;
Mike McCormackbf554572001-08-23 23:29:20 +000061 enum pipe_state state;
62 struct pipe_user *other;
Mike McCormackde7c3002001-07-10 19:16:49 +000063 struct named_pipe *pipe;
64 struct pipe_user *next;
65 struct pipe_user *prev;
Marcus Meissner93c3fae2002-01-12 21:16:13 +000066 struct thread *thread;
Mike McCormack309ed4e2001-11-07 20:14:45 +000067 void *func;
68 void *overlapped;
Mike McCormackde7c3002001-07-10 19:16:49 +000069};
70
71struct named_pipe
72{
73 struct object obj; /* object header */
74 unsigned int pipemode;
75 unsigned int maxinstances;
76 unsigned int outsize;
77 unsigned int insize;
78 unsigned int timeout;
79 struct pipe_user *users;
80};
81
82static void named_pipe_dump( struct object *obj, int verbose );
83static void named_pipe_destroy( struct object *obj);
84
85static const struct object_ops named_pipe_ops =
86{
87 sizeof(struct named_pipe), /* size */
88 named_pipe_dump, /* dump */
89 no_add_queue, /* add_queue */
90 NULL, /* remove_queue */
91 NULL, /* signaled */
92 NULL, /* satisfied */
93 NULL, /* get_poll_events */
94 NULL, /* poll_event */
95 no_get_fd, /* get_fd */
96 no_flush, /* flush */
97 no_get_file_info, /* get_file_info */
Mike McCormack6f011c02001-12-20 00:07:05 +000098 NULL, /* queue_async */
Mike McCormackde7c3002001-07-10 19:16:49 +000099 named_pipe_destroy /* destroy */
100};
101
102static void pipe_user_dump( struct object *obj, int verbose );
103static void pipe_user_destroy( struct object *obj);
104static int pipe_user_get_fd( struct object *obj );
Martin Wilck88cd32b2002-01-09 20:30:51 +0000105static int pipe_user_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags );
Mike McCormackde7c3002001-07-10 19:16:49 +0000106
107static const struct object_ops pipe_user_ops =
108{
109 sizeof(struct pipe_user), /* size */
110 pipe_user_dump, /* dump */
111 default_poll_add_queue, /* add_queue */
112 default_poll_remove_queue, /* remove_queue */
113 default_poll_signaled, /* signaled */
114 no_satisfied, /* satisfied */
115 NULL, /* get_poll_events */
116 default_poll_event, /* poll_event */
117 pipe_user_get_fd, /* get_fd */
118 no_flush, /* flush */
Alexandre Julliard646d6212001-10-05 19:45:45 +0000119 pipe_user_get_info, /* get_file_info */
Mike McCormack6f011c02001-12-20 00:07:05 +0000120 NULL, /* queue_async */
Mike McCormackde7c3002001-07-10 19:16:49 +0000121 pipe_user_destroy /* destroy */
122};
123
124static void named_pipe_dump( struct object *obj, int verbose )
125{
126 struct named_pipe *pipe = (struct named_pipe *)obj;
127 assert( obj->ops == &named_pipe_ops );
128 fprintf( stderr, "named pipe %p\n" ,pipe);
129}
130
131static void pipe_user_dump( struct object *obj, int verbose )
132{
133 struct pipe_user *user = (struct pipe_user *)obj;
134 assert( obj->ops == &pipe_user_ops );
Mike McCormackbf554572001-08-23 23:29:20 +0000135 fprintf( stderr, "named pipe user %p (state %d)\n", user, user->state );
Mike McCormackde7c3002001-07-10 19:16:49 +0000136}
137
138static void named_pipe_destroy( struct object *obj)
139{
140 struct named_pipe *pipe = (struct named_pipe *)obj;
141 assert( !pipe->users );
142}
143
Mike McCormack309ed4e2001-11-07 20:14:45 +0000144static void notify_waiter( struct pipe_user *user, unsigned int status)
145{
146 if(user->thread && user->func && user->overlapped)
147 {
148 /* queue a system APC, to notify a waiting thread */
149 thread_queue_apc(user->thread,NULL,user->func,
150 APC_ASYNC,1,2,user->overlapped,status);
151 }
Marcus Meissner93c3fae2002-01-12 21:16:13 +0000152 if (user->thread) release_object(user->thread);
Mike McCormack309ed4e2001-11-07 20:14:45 +0000153 user->thread = NULL;
154 user->func = NULL;
155 user->overlapped=NULL;
156}
157
Mike McCormackde7c3002001-07-10 19:16:49 +0000158static void pipe_user_destroy( struct object *obj)
159{
160 struct pipe_user *user = (struct pipe_user *)obj;
161
162 assert( obj->ops == &pipe_user_ops );
163
Mike McCormack309ed4e2001-11-07 20:14:45 +0000164 if(user->overlapped)
165 notify_waiter(user,STATUS_HANDLES_CLOSED);
166
Mike McCormackbf554572001-08-23 23:29:20 +0000167 if(user->other)
168 {
169 close(user->other->obj.fd);
170 user->other->obj.fd = -1;
171 switch(user->other->state)
172 {
173 case ps_connected_server:
174 user->other->state = ps_idle_server;
175 break;
176 case ps_connected_client:
177 user->other->state = ps_disconnected;
178 break;
179 default:
180 fprintf(stderr,"connected pipe has strange state %d!\n",
181 user->other->state);
182 }
183 user->other->other=NULL;
184 user->other = NULL;
185 }
Mike McCormackde7c3002001-07-10 19:16:49 +0000186
187 /* remove user from pipe's user list */
188 if (user->next) user->next->prev = user->prev;
189 if (user->prev) user->prev->next = user->next;
190 else user->pipe->users = user->next;
Marcus Meissner93c3fae2002-01-12 21:16:13 +0000191 if (user->thread) release_object(user->thread);
Mike McCormackde7c3002001-07-10 19:16:49 +0000192 release_object(user->pipe);
193}
194
195static int pipe_user_get_fd( struct object *obj )
196{
197 struct pipe_user *user = (struct pipe_user *)obj;
198 assert( obj->ops == &pipe_user_ops );
199 return user->obj.fd;
200}
201
Martin Wilck88cd32b2002-01-09 20:30:51 +0000202static int pipe_user_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags )
Alexandre Julliard646d6212001-10-05 19:45:45 +0000203{
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000204 if (reply)
Alexandre Julliard646d6212001-10-05 19:45:45 +0000205 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000206 reply->type = FILE_TYPE_PIPE;
207 reply->attr = 0;
208 reply->access_time = 0;
209 reply->write_time = 0;
210 reply->size_high = 0;
211 reply->size_low = 0;
212 reply->links = 0;
213 reply->index_high = 0;
214 reply->index_low = 0;
215 reply->serial = 0;
Alexandre Julliard646d6212001-10-05 19:45:45 +0000216 }
Martin Wilck88cd32b2002-01-09 20:30:51 +0000217 *flags = 0;
Alexandre Julliard646d6212001-10-05 19:45:45 +0000218 return FD_TYPE_DEFAULT;
219}
220
Mike McCormackde7c3002001-07-10 19:16:49 +0000221static struct named_pipe *create_named_pipe( const WCHAR *name, size_t len )
222{
223 struct named_pipe *pipe;
224
225 if ((pipe = create_named_object( &named_pipe_ops, name, len )))
226 {
227 if (get_error() != STATUS_OBJECT_NAME_COLLISION)
228 {
229 /* initialize it if it didn't already exist */
230 pipe->users = 0;
231 }
232 }
233 return pipe;
234}
235
236static struct pipe_user *get_pipe_user_obj( struct process *process, handle_t handle,
237 unsigned int access )
238{
239 return (struct pipe_user *)get_handle_obj( process, handle, access, &pipe_user_ops );
240}
241
242static struct pipe_user *create_pipe_user( struct named_pipe *pipe, int fd )
243{
244 struct pipe_user *user;
Mike McCormackde7c3002001-07-10 19:16:49 +0000245
Mike McCormackbf554572001-08-23 23:29:20 +0000246 user = alloc_object( &pipe_user_ops, fd );
Mike McCormackde7c3002001-07-10 19:16:49 +0000247 if(!user)
Mike McCormackde7c3002001-07-10 19:16:49 +0000248 return NULL;
Mike McCormackde7c3002001-07-10 19:16:49 +0000249
250 user->pipe = pipe;
Mike McCormackbf554572001-08-23 23:29:20 +0000251 user->state = ps_none;
Mike McCormackbf554572001-08-23 23:29:20 +0000252 user->other = NULL;
Mike McCormack309ed4e2001-11-07 20:14:45 +0000253 user->thread = NULL;
254 user->func = NULL;
255 user->overlapped = NULL;
Mike McCormackde7c3002001-07-10 19:16:49 +0000256
257 /* add to list of pipe users */
258 if ((user->next = pipe->users)) user->next->prev = user;
259 user->prev = NULL;
260 pipe->users = user;
261
262 grab_object(pipe);
263
264 return user;
Mike McCormackde7c3002001-07-10 19:16:49 +0000265}
266
Mike McCormackbf554572001-08-23 23:29:20 +0000267static struct pipe_user *find_partner(struct named_pipe *pipe, enum pipe_state state)
Mike McCormackde7c3002001-07-10 19:16:49 +0000268{
269 struct pipe_user *x;
270
271 for(x = pipe->users; x; x=x->next)
272 {
Mike McCormackbf554572001-08-23 23:29:20 +0000273 if(x->state==state)
Mike McCormackde7c3002001-07-10 19:16:49 +0000274 break;
275 }
276
Mike McCormackbf554572001-08-23 23:29:20 +0000277 if(!x)
278 return NULL;
279
Mike McCormackde7c3002001-07-10 19:16:49 +0000280 return (struct pipe_user *)grab_object( x );
281}
282
283DECL_HANDLER(create_named_pipe)
284{
285 struct named_pipe *pipe;
286 struct pipe_user *user;
287
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000288 reply->handle = 0;
289 pipe = create_named_pipe( get_req_data(), get_req_data_size() );
Mike McCormackde7c3002001-07-10 19:16:49 +0000290 if(!pipe)
291 return;
292
Mike McCormackf2e7ce72001-08-27 19:03:42 +0000293 if (get_error() != STATUS_OBJECT_NAME_COLLISION)
294 {
295 pipe->insize = req->insize;
296 pipe->outsize = req->outsize;
297 pipe->maxinstances = req->maxinstances;
298 pipe->timeout = req->timeout;
299 pipe->pipemode = req->pipemode;
300 }
301
Mike McCormackde7c3002001-07-10 19:16:49 +0000302 user = create_pipe_user (pipe, -1);
303
304 if(user)
305 {
Mike McCormackbf554572001-08-23 23:29:20 +0000306 user->state = ps_idle_server;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000307 reply->handle = alloc_handle( current->process, user, GENERIC_READ|GENERIC_WRITE, 0 );
Mike McCormackde7c3002001-07-10 19:16:49 +0000308 release_object( user );
309 }
310
311 release_object( pipe );
312}
313
314DECL_HANDLER(open_named_pipe)
315{
316 struct named_pipe *pipe;
Mike McCormackde7c3002001-07-10 19:16:49 +0000317
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000318 reply->handle = 0;
319 pipe = create_named_pipe( get_req_data(), get_req_data_size() );
Mike McCormackde7c3002001-07-10 19:16:49 +0000320 if(!pipe)
321 return;
322
323 if (get_error() == STATUS_OBJECT_NAME_COLLISION)
324 {
Mike McCormackbf554572001-08-23 23:29:20 +0000325 struct pipe_user *partner;
326
327 if ((partner = find_partner(pipe, ps_wait_open)))
Mike McCormackde7c3002001-07-10 19:16:49 +0000328 {
Mike McCormackbf554572001-08-23 23:29:20 +0000329 int fds[2];
330
331 if(!socketpair(PF_UNIX, SOCK_STREAM, 0, fds))
Mike McCormackde7c3002001-07-10 19:16:49 +0000332 {
Mike McCormackbf554572001-08-23 23:29:20 +0000333 struct pipe_user *user;
334
335 if( (user = create_pipe_user (pipe, fds[1])) )
336 {
337 partner->obj.fd = fds[0];
Mike McCormack309ed4e2001-11-07 20:14:45 +0000338 notify_waiter(partner,STATUS_SUCCESS);
Mike McCormackbf554572001-08-23 23:29:20 +0000339 partner->state = ps_connected_server;
340 partner->other = user;
341 user->state = ps_connected_client;
342 user->other = partner;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000343 reply->handle = alloc_handle( current->process, user, req->access, 0 );
Mike McCormackbf554572001-08-23 23:29:20 +0000344 release_object(user);
345 }
346 else
347 {
348 close(fds[0]);
349 }
Mike McCormackde7c3002001-07-10 19:16:49 +0000350 }
351 release_object( partner );
352 }
Mike McCormackbf554572001-08-23 23:29:20 +0000353 else
354 {
Ove Kaaven705e7d72001-07-17 00:38:00 +0000355 set_error(STATUS_PIPE_NOT_AVAILABLE);
Mike McCormackde7c3002001-07-10 19:16:49 +0000356 }
357 }
Mike McCormackbf554572001-08-23 23:29:20 +0000358 else
359 {
Mike McCormackde7c3002001-07-10 19:16:49 +0000360 set_error(STATUS_NO_SUCH_FILE);
361 }
362
363 release_object(pipe);
364}
365
366DECL_HANDLER(connect_named_pipe)
367{
Mike McCormackbf554572001-08-23 23:29:20 +0000368 struct pipe_user *user, *partner;
Mike McCormackde7c3002001-07-10 19:16:49 +0000369
370 user = get_pipe_user_obj(current->process, req->handle, 0);
371 if(!user)
372 return;
373
Mike McCormackbf554572001-08-23 23:29:20 +0000374 if( user->state != ps_idle_server )
Mike McCormackde7c3002001-07-10 19:16:49 +0000375 {
Mike McCormackde7c3002001-07-10 19:16:49 +0000376 set_error(STATUS_PORT_ALREADY_SET);
377 }
378 else
379 {
Mike McCormackbf554572001-08-23 23:29:20 +0000380 user->state = ps_wait_open;
Marcus Meissner93c3fae2002-01-12 21:16:13 +0000381 user->thread = (struct thread *)grab_object(current);
Mike McCormack309ed4e2001-11-07 20:14:45 +0000382 user->func = req->func;
383 user->overlapped = req->overlapped;
Mike McCormackbf554572001-08-23 23:29:20 +0000384
385 /* notify all waiters that a pipe just became available */
386 while( (partner = find_partner(user->pipe,ps_wait_connect)) )
387 {
Mike McCormack309ed4e2001-11-07 20:14:45 +0000388 notify_waiter(partner,STATUS_SUCCESS);
Mike McCormackbf554572001-08-23 23:29:20 +0000389 release_object(partner);
390 release_object(partner);
391 }
Mike McCormackde7c3002001-07-10 19:16:49 +0000392 }
393
394 release_object(user);
395}
Mike McCormackbf554572001-08-23 23:29:20 +0000396
397DECL_HANDLER(wait_named_pipe)
398{
Mike McCormackbf554572001-08-23 23:29:20 +0000399 struct named_pipe *pipe;
400
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000401 pipe = create_named_pipe( get_req_data(), get_req_data_size() );
Mike McCormackbf554572001-08-23 23:29:20 +0000402 if( pipe )
403 {
404 /* only wait if the pipe already exists */
405 if(get_error() == STATUS_OBJECT_NAME_COLLISION)
406 {
407 struct pipe_user *partner;
408
409 set_error(STATUS_SUCCESS);
410 if( (partner = find_partner(pipe,ps_wait_open)) )
411 {
Mike McCormack309ed4e2001-11-07 20:14:45 +0000412 /* this should use notify_waiter,
413 but no pipe_user object exists now... */
414 thread_queue_apc(current,NULL,req->func,
415 APC_ASYNC,1,2,req->overlapped,STATUS_SUCCESS);
Mike McCormackbf554572001-08-23 23:29:20 +0000416 release_object(partner);
417 }
418 else
419 {
420 struct pipe_user *user;
421
422 if( (user = create_pipe_user (pipe, -1)) )
423 {
Mike McCormackbf554572001-08-23 23:29:20 +0000424 user->state = ps_wait_connect;
Marcus Meissner93c3fae2002-01-12 21:16:13 +0000425 user->thread = (struct thread *)grab_object(current);
Mike McCormack309ed4e2001-11-07 20:14:45 +0000426 user->func = req->func;
427 user->overlapped = req->overlapped;
Mike McCormackbf554572001-08-23 23:29:20 +0000428 /* don't release it */
429 }
430 }
431 }
432 else
433 {
434 set_error(STATUS_PIPE_NOT_AVAILABLE);
435 }
436 release_object(pipe);
437 }
Mike McCormackbf554572001-08-23 23:29:20 +0000438}
439
440DECL_HANDLER(disconnect_named_pipe)
441{
442 struct pipe_user *user;
443
444 user = get_pipe_user_obj(current->process, req->handle, 0);
445 if(!user)
446 return;
447 if( (user->state == ps_connected_server) &&
448 (user->other->state == ps_connected_client) )
449 {
450 close(user->other->obj.fd);
451 user->other->obj.fd = -1;
452 user->other->state = ps_disconnected;
453 user->other->other = NULL;
454
455 close(user->obj.fd);
456 user->obj.fd = -1;
457 user->state = ps_idle_server;
458 user->other = NULL;
459 }
460 release_object(user);
461}
Mike McCormackf2e7ce72001-08-27 19:03:42 +0000462
463DECL_HANDLER(get_named_pipe_info)
464{
465 struct pipe_user *user;
466
467 user = get_pipe_user_obj(current->process, req->handle, 0);
468 if(!user)
469 return;
470
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000471 reply->flags = user->pipe->pipemode;
472 reply->maxinstances = user->pipe->maxinstances;
473 reply->insize = user->pipe->insize;
474 reply->outsize = user->pipe->outsize;
Mike McCormackf2e7ce72001-08-27 19:03:42 +0000475
476 release_object(user);
477}
478