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