More general approach to file descriptor types and flags.
[wine] / server / named_pipe.c
1 /*
2  * Server-side pipe management
3  *
4  * Copyright (C) 1998 Alexandre Julliard
5  * Copyright (C) 2001 Mike McCormack
6  *
7  * TODO:
8  *   improve error handling
9  */
10
11 #include "config.h"
12
13 #include <assert.h>
14 #include <fcntl.h>
15 #include <string.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <sys/time.h>
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <time.h>
22 #include <unistd.h>
23
24 #include "winbase.h"
25
26 #include "handle.h"
27 #include "thread.h"
28 #include "request.h"
29
30 enum pipe_state
31 {
32     ps_none,
33     ps_idle_server,
34     ps_wait_open,
35     ps_wait_connect,
36     ps_connected_server,
37     ps_connected_client,
38     ps_disconnected
39 };
40
41 struct named_pipe;
42
43 struct pipe_user
44 {
45     struct object       obj;
46     enum pipe_state     state;
47     struct pipe_user   *other;
48     struct named_pipe  *pipe;
49     struct pipe_user   *next;
50     struct pipe_user   *prev;
51     void               *thread;
52     void               *func;
53     void               *overlapped;
54 };
55
56 struct named_pipe
57 {
58     struct object       obj;         /* object header */
59     unsigned int        pipemode;
60     unsigned int        maxinstances;
61     unsigned int        outsize;
62     unsigned int        insize;
63     unsigned int        timeout;
64     struct pipe_user   *users;
65 };
66
67 static void named_pipe_dump( struct object *obj, int verbose );
68 static void named_pipe_destroy( struct object *obj);
69
70 static const struct object_ops named_pipe_ops =
71 {
72     sizeof(struct named_pipe),    /* size */
73     named_pipe_dump,              /* dump */
74     no_add_queue,                 /* add_queue */
75     NULL,                         /* remove_queue */
76     NULL,                         /* signaled */
77     NULL,                         /* satisfied */
78     NULL,                         /* get_poll_events */
79     NULL,                         /* poll_event */
80     no_get_fd,                    /* get_fd */
81     no_flush,                     /* flush */
82     no_get_file_info,             /* get_file_info */
83     NULL,                         /* queue_async */
84     named_pipe_destroy            /* destroy */
85 };
86
87 static void pipe_user_dump( struct object *obj, int verbose );
88 static void pipe_user_destroy( struct object *obj);
89 static int pipe_user_get_fd( struct object *obj );
90 static int pipe_user_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags );
91
92 static const struct object_ops pipe_user_ops =
93 {
94     sizeof(struct pipe_user),     /* size */
95     pipe_user_dump,               /* dump */
96     default_poll_add_queue,       /* add_queue */
97     default_poll_remove_queue,    /* remove_queue */
98     default_poll_signaled,        /* signaled */
99     no_satisfied,                 /* satisfied */
100     NULL,                         /* get_poll_events */
101     default_poll_event,           /* poll_event */
102     pipe_user_get_fd,             /* get_fd */
103     no_flush,                     /* flush */
104     pipe_user_get_info,           /* get_file_info */
105     NULL,                         /* queue_async */
106     pipe_user_destroy             /* destroy */
107 };
108
109 static void named_pipe_dump( struct object *obj, int verbose )
110 {
111     struct named_pipe *pipe = (struct named_pipe *)obj;
112     assert( obj->ops == &named_pipe_ops );
113     fprintf( stderr, "named pipe %p\n" ,pipe);
114 }
115
116 static void pipe_user_dump( struct object *obj, int verbose )
117 {
118     struct pipe_user *user = (struct pipe_user *)obj;
119     assert( obj->ops == &pipe_user_ops );
120     fprintf( stderr, "named pipe user %p (state %d)\n", user, user->state );
121 }
122
123 static void named_pipe_destroy( struct object *obj)
124 {
125     struct named_pipe *pipe = (struct named_pipe *)obj;
126     assert( !pipe->users );
127 }
128
129 static void notify_waiter( struct pipe_user *user, unsigned int status)
130 {
131     if(user->thread && user->func && user->overlapped)
132     {
133         /* queue a system APC, to notify a waiting thread */
134         thread_queue_apc(user->thread,NULL,user->func,
135             APC_ASYNC,1,2,user->overlapped,status);
136     }
137     user->thread = NULL;
138     user->func = NULL;
139     user->overlapped=NULL;
140 }
141
142 static void pipe_user_destroy( struct object *obj)
143 {
144     struct pipe_user *user = (struct pipe_user *)obj;
145
146     assert( obj->ops == &pipe_user_ops );
147
148     if(user->overlapped)
149         notify_waiter(user,STATUS_HANDLES_CLOSED);
150
151     if(user->other)
152     {
153         close(user->other->obj.fd);
154         user->other->obj.fd = -1;
155         switch(user->other->state)
156         {
157         case ps_connected_server:
158             user->other->state = ps_idle_server;
159             break;
160         case ps_connected_client:
161             user->other->state = ps_disconnected;
162             break;
163         default:
164             fprintf(stderr,"connected pipe has strange state %d!\n",
165                             user->other->state);
166         }
167         user->other->other=NULL;
168         user->other = NULL;
169     }
170
171     /* remove user from pipe's user list */
172     if (user->next) user->next->prev = user->prev;
173     if (user->prev) user->prev->next = user->next;
174     else user->pipe->users = user->next;
175     release_object(user->pipe);
176 }
177
178 static int pipe_user_get_fd( struct object *obj )
179 {
180     struct pipe_user *user = (struct pipe_user *)obj;
181     assert( obj->ops == &pipe_user_ops );
182     return user->obj.fd;
183 }
184
185 static int pipe_user_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags )
186 {
187     if (reply)
188     {
189         reply->type        = FILE_TYPE_PIPE;
190         reply->attr        = 0;
191         reply->access_time = 0;
192         reply->write_time  = 0;
193         reply->size_high   = 0;
194         reply->size_low    = 0;
195         reply->links       = 0;
196         reply->index_high  = 0;
197         reply->index_low   = 0;
198         reply->serial      = 0;
199     }
200     *flags = 0;
201     return FD_TYPE_DEFAULT;
202 }
203
204 static struct named_pipe *create_named_pipe( const WCHAR *name, size_t len )
205 {
206     struct named_pipe *pipe;
207
208     if ((pipe = create_named_object( &named_pipe_ops, name, len )))
209     {
210         if (get_error() != STATUS_OBJECT_NAME_COLLISION)
211         {
212             /* initialize it if it didn't already exist */
213             pipe->users = 0;
214         }
215     }
216     return pipe;
217 }
218
219 static struct pipe_user *get_pipe_user_obj( struct process *process, handle_t handle,
220                                             unsigned int access )
221 {
222     return (struct pipe_user *)get_handle_obj( process, handle, access, &pipe_user_ops );
223 }
224
225 static struct pipe_user *create_pipe_user( struct named_pipe *pipe, int fd )
226 {
227     struct pipe_user *user;
228
229     user = alloc_object( &pipe_user_ops, fd );
230     if(!user)
231         return NULL;
232
233     user->pipe = pipe;
234     user->state = ps_none;
235     user->other = NULL;
236     user->thread = NULL;
237     user->func = NULL;
238     user->overlapped = NULL;
239
240     /* add to list of pipe users */
241     if ((user->next = pipe->users)) user->next->prev = user;
242     user->prev = NULL;
243     pipe->users = user;
244
245     grab_object(pipe);
246
247     return user;
248 }
249
250 static struct pipe_user *find_partner(struct named_pipe *pipe, enum pipe_state state)
251 {
252     struct pipe_user *x;
253
254     for(x = pipe->users; x; x=x->next)
255     {
256         if(x->state==state)
257         break;
258     }
259
260     if(!x)
261         return NULL;
262
263     return (struct pipe_user *)grab_object( x );
264 }
265
266 DECL_HANDLER(create_named_pipe)
267 {
268     struct named_pipe *pipe;
269     struct pipe_user *user;
270
271     reply->handle = 0;
272     pipe = create_named_pipe( get_req_data(), get_req_data_size() );
273     if(!pipe)
274         return;
275
276     if (get_error() != STATUS_OBJECT_NAME_COLLISION)
277     {
278         pipe->insize = req->insize;
279         pipe->outsize = req->outsize;
280         pipe->maxinstances = req->maxinstances;
281         pipe->timeout = req->timeout;
282         pipe->pipemode = req->pipemode;
283     }
284
285     user = create_pipe_user (pipe, -1);
286
287     if(user)
288     {
289         user->state = ps_idle_server;
290         reply->handle = alloc_handle( current->process, user, GENERIC_READ|GENERIC_WRITE, 0 );
291         release_object( user );
292     }
293
294     release_object( pipe );
295 }
296
297 DECL_HANDLER(open_named_pipe)
298 {
299     struct named_pipe *pipe;
300
301     reply->handle = 0;
302     pipe = create_named_pipe( get_req_data(), get_req_data_size() );
303     if(!pipe)
304         return;
305
306     if (get_error() == STATUS_OBJECT_NAME_COLLISION)
307     {
308         struct pipe_user *partner;
309
310         if ((partner = find_partner(pipe, ps_wait_open)))
311         {
312             int fds[2];
313
314             if(!socketpair(PF_UNIX, SOCK_STREAM, 0, fds))
315             {
316                 struct pipe_user *user;
317
318                 if( (user = create_pipe_user (pipe, fds[1])) )
319                 {
320                     partner->obj.fd = fds[0];
321                     notify_waiter(partner,STATUS_SUCCESS);
322                     partner->state = ps_connected_server;
323                     partner->other = user;
324                     user->state = ps_connected_client;
325                     user->other = partner;
326                     reply->handle = alloc_handle( current->process, user, req->access, 0 );
327                     release_object(user);
328                 }
329                 else
330                 {
331                     close(fds[0]);
332                 }
333             }
334             release_object( partner );
335         }
336         else
337         {
338             set_error(STATUS_PIPE_NOT_AVAILABLE);
339         }
340     }
341     else
342     {
343         set_error(STATUS_NO_SUCH_FILE);
344     }
345
346     release_object(pipe);
347 }
348
349 DECL_HANDLER(connect_named_pipe)
350 {
351     struct pipe_user *user, *partner;
352
353     user = get_pipe_user_obj(current->process, req->handle, 0);
354     if(!user)
355         return;
356
357     if( user->state != ps_idle_server )
358     {
359         set_error(STATUS_PORT_ALREADY_SET);
360     }
361     else
362     {
363         user->state = ps_wait_open;
364         user->thread = current;
365         user->func = req->func;
366         user->overlapped = req->overlapped;
367
368         /* notify all waiters that a pipe just became available */
369         while( (partner = find_partner(user->pipe,ps_wait_connect)) )
370         {
371             notify_waiter(partner,STATUS_SUCCESS);
372             release_object(partner);
373             release_object(partner);
374         }
375     }
376
377     release_object(user);
378 }
379
380 DECL_HANDLER(wait_named_pipe)
381 {
382     struct named_pipe *pipe;
383
384     pipe = create_named_pipe( get_req_data(), get_req_data_size() );
385     if( pipe )
386     {
387         /* only wait if the pipe already exists */
388         if(get_error() == STATUS_OBJECT_NAME_COLLISION)
389         {
390             struct pipe_user *partner;
391
392             set_error(STATUS_SUCCESS);
393             if( (partner = find_partner(pipe,ps_wait_open)) )
394             {
395                 /* this should use notify_waiter, 
396                    but no pipe_user object exists now... */
397                 thread_queue_apc(current,NULL,req->func,
398                     APC_ASYNC,1,2,req->overlapped,STATUS_SUCCESS);
399                 release_object(partner);
400             }
401             else
402             {
403                 struct pipe_user *user;
404
405                 if( (user = create_pipe_user (pipe, -1)) )
406                 {
407                     user->state = ps_wait_connect;
408                     user->thread = current;
409                     user->func = req->func;
410                     user->overlapped = req->overlapped;
411                     /* don't release it */
412                 }
413             }
414         }
415         else
416         {
417             set_error(STATUS_PIPE_NOT_AVAILABLE);
418         }
419         release_object(pipe);
420     }
421 }
422
423 DECL_HANDLER(disconnect_named_pipe)
424 {
425     struct pipe_user *user;
426
427     user = get_pipe_user_obj(current->process, req->handle, 0);
428     if(!user)
429         return;
430     if( (user->state == ps_connected_server) &&
431         (user->other->state == ps_connected_client) )
432     {
433         close(user->other->obj.fd);
434         user->other->obj.fd = -1;
435         user->other->state = ps_disconnected;
436         user->other->other = NULL;
437
438         close(user->obj.fd);
439         user->obj.fd = -1;
440         user->state = ps_idle_server;
441         user->other = NULL;
442     }
443     release_object(user);
444 }
445
446 DECL_HANDLER(get_named_pipe_info)
447 {
448     struct pipe_user *user;
449
450     user = get_pipe_user_obj(current->process, req->handle, 0);
451     if(!user)
452         return;
453
454     reply->flags        = user->pipe->pipemode;
455     reply->maxinstances = user->pipe->maxinstances;
456     reply->insize       = user->pipe->insize;
457     reply->outsize      = user->pipe->outsize;
458
459     release_object(user);
460 }
461