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