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