- Add some undocumented ioctl mappings.
[wine.git] / server / named_pipe.c
blobecad8c149b1305cb26dd2ed380acb3b60698882d
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 #include <sys/socket.h>
36 #include <time.h>
37 #include <unistd.h>
39 #include "winbase.h"
41 #include "handle.h"
42 #include "thread.h"
43 #include "request.h"
45 enum pipe_state
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
56 struct named_pipe;
58 struct pipe_user
60 struct object obj;
61 enum pipe_state state;
62 struct pipe_user *other;
63 struct named_pipe *pipe;
64 struct pipe_user *next;
65 struct pipe_user *prev;
66 struct thread *thread;
67 void *func;
68 void *overlapped;
71 struct named_pipe
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;
82 static void named_pipe_dump( struct object *obj, int verbose );
83 static void named_pipe_destroy( struct object *obj);
85 static const struct object_ops named_pipe_ops =
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 */
98 NULL, /* queue_async */
99 named_pipe_destroy /* destroy */
102 static void pipe_user_dump( struct object *obj, int verbose );
103 static void pipe_user_destroy( struct object *obj);
104 static int pipe_user_get_fd( struct object *obj );
105 static int pipe_user_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags );
107 static const struct object_ops pipe_user_ops =
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 */
119 pipe_user_get_info, /* get_file_info */
120 NULL, /* queue_async */
121 pipe_user_destroy /* destroy */
124 static void named_pipe_dump( struct object *obj, int verbose )
126 struct named_pipe *pipe = (struct named_pipe *)obj;
127 assert( obj->ops == &named_pipe_ops );
128 fprintf( stderr, "named pipe %p\n" ,pipe);
131 static void pipe_user_dump( struct object *obj, int verbose )
133 struct pipe_user *user = (struct pipe_user *)obj;
134 assert( obj->ops == &pipe_user_ops );
135 fprintf( stderr, "named pipe user %p (state %d)\n", user, user->state );
138 static void named_pipe_destroy( struct object *obj)
140 struct named_pipe *pipe = (struct named_pipe *)obj;
141 assert( !pipe->users );
144 static void notify_waiter( struct pipe_user *user, unsigned int status)
146 if(user->thread && user->func && user->overlapped)
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);
152 if (user->thread) release_object(user->thread);
153 user->thread = NULL;
154 user->func = NULL;
155 user->overlapped=NULL;
158 static void pipe_user_destroy( struct object *obj)
160 struct pipe_user *user = (struct pipe_user *)obj;
162 assert( obj->ops == &pipe_user_ops );
164 if(user->overlapped)
165 notify_waiter(user,STATUS_HANDLES_CLOSED);
167 if(user->other)
169 close(user->other->obj.fd);
170 user->other->obj.fd = -1;
171 switch(user->other->state)
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);
183 user->other->other=NULL;
184 user->other = NULL;
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;
191 if (user->thread) release_object(user->thread);
192 release_object(user->pipe);
195 static int pipe_user_get_fd( struct object *obj )
197 struct pipe_user *user = (struct pipe_user *)obj;
198 assert( obj->ops == &pipe_user_ops );
199 return user->obj.fd;
202 static int pipe_user_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags )
204 if (reply)
206 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;
217 *flags = 0;
218 return FD_TYPE_DEFAULT;
221 static struct named_pipe *create_named_pipe( const WCHAR *name, size_t len )
223 struct named_pipe *pipe;
225 if ((pipe = create_named_object( &named_pipe_ops, name, len )))
227 if (get_error() != STATUS_OBJECT_NAME_COLLISION)
229 /* initialize it if it didn't already exist */
230 pipe->users = 0;
233 return pipe;
236 static struct pipe_user *get_pipe_user_obj( struct process *process, handle_t handle,
237 unsigned int access )
239 return (struct pipe_user *)get_handle_obj( process, handle, access, &pipe_user_ops );
242 static struct pipe_user *create_pipe_user( struct named_pipe *pipe, int fd )
244 struct pipe_user *user;
246 user = alloc_object( &pipe_user_ops, fd );
247 if(!user)
248 return NULL;
250 user->pipe = pipe;
251 user->state = ps_none;
252 user->other = NULL;
253 user->thread = NULL;
254 user->func = NULL;
255 user->overlapped = NULL;
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;
262 grab_object(pipe);
264 return user;
267 static struct pipe_user *find_partner(struct named_pipe *pipe, enum pipe_state state)
269 struct pipe_user *x;
271 for(x = pipe->users; x; x=x->next)
273 if(x->state==state)
274 break;
277 if(!x)
278 return NULL;
280 return (struct pipe_user *)grab_object( x );
283 DECL_HANDLER(create_named_pipe)
285 struct named_pipe *pipe;
286 struct pipe_user *user;
288 reply->handle = 0;
289 pipe = create_named_pipe( get_req_data(), get_req_data_size() );
290 if(!pipe)
291 return;
293 if (get_error() != STATUS_OBJECT_NAME_COLLISION)
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;
302 user = create_pipe_user (pipe, -1);
304 if(user)
306 user->state = ps_idle_server;
307 reply->handle = alloc_handle( current->process, user, GENERIC_READ|GENERIC_WRITE, 0 );
308 release_object( user );
311 release_object( pipe );
314 DECL_HANDLER(open_named_pipe)
316 struct named_pipe *pipe;
318 reply->handle = 0;
319 pipe = create_named_pipe( get_req_data(), get_req_data_size() );
320 if(!pipe)
321 return;
323 if (get_error() == STATUS_OBJECT_NAME_COLLISION)
325 struct pipe_user *partner;
327 if ((partner = find_partner(pipe, ps_wait_open)))
329 int fds[2];
331 if(!socketpair(PF_UNIX, SOCK_STREAM, 0, fds))
333 struct pipe_user *user;
335 if( (user = create_pipe_user (pipe, fds[1])) )
337 partner->obj.fd = fds[0];
338 notify_waiter(partner,STATUS_SUCCESS);
339 partner->state = ps_connected_server;
340 partner->other = user;
341 user->state = ps_connected_client;
342 user->other = partner;
343 reply->handle = alloc_handle( current->process, user, req->access, 0 );
344 release_object(user);
346 else
348 close(fds[0]);
351 release_object( partner );
353 else
355 set_error(STATUS_PIPE_NOT_AVAILABLE);
358 else
360 set_error(STATUS_NO_SUCH_FILE);
363 release_object(pipe);
366 DECL_HANDLER(connect_named_pipe)
368 struct pipe_user *user, *partner;
370 user = get_pipe_user_obj(current->process, req->handle, 0);
371 if(!user)
372 return;
374 if( user->state != ps_idle_server )
376 set_error(STATUS_PORT_ALREADY_SET);
378 else
380 user->state = ps_wait_open;
381 user->thread = (struct thread *)grab_object(current);
382 user->func = req->func;
383 user->overlapped = req->overlapped;
385 /* notify all waiters that a pipe just became available */
386 while( (partner = find_partner(user->pipe,ps_wait_connect)) )
388 notify_waiter(partner,STATUS_SUCCESS);
389 release_object(partner);
390 release_object(partner);
394 release_object(user);
397 DECL_HANDLER(wait_named_pipe)
399 struct named_pipe *pipe;
401 pipe = create_named_pipe( get_req_data(), get_req_data_size() );
402 if( pipe )
404 /* only wait if the pipe already exists */
405 if(get_error() == STATUS_OBJECT_NAME_COLLISION)
407 struct pipe_user *partner;
409 set_error(STATUS_SUCCESS);
410 if( (partner = find_partner(pipe,ps_wait_open)) )
412 /* 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);
416 release_object(partner);
418 else
420 struct pipe_user *user;
422 if( (user = create_pipe_user (pipe, -1)) )
424 user->state = ps_wait_connect;
425 user->thread = (struct thread *)grab_object(current);
426 user->func = req->func;
427 user->overlapped = req->overlapped;
428 /* don't release it */
432 else
434 set_error(STATUS_PIPE_NOT_AVAILABLE);
436 release_object(pipe);
440 DECL_HANDLER(disconnect_named_pipe)
442 struct pipe_user *user;
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) )
450 close(user->other->obj.fd);
451 user->other->obj.fd = -1;
452 user->other->state = ps_disconnected;
453 user->other->other = NULL;
455 close(user->obj.fd);
456 user->obj.fd = -1;
457 user->state = ps_idle_server;
458 user->other = NULL;
460 release_object(user);
463 DECL_HANDLER(get_named_pipe_info)
465 struct pipe_user *user;
467 user = get_pipe_user_obj(current->process, req->handle, 0);
468 if(!user)
469 return;
471 reply->flags = user->pipe->pipemode;
472 reply->maxinstances = user->pipe->maxinstances;
473 reply->insize = user->pipe->insize;
474 reply->outsize = user->pipe->outsize;
476 release_object(user);