Save the registry before exiting on a SIGTERM.
[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 );
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 )
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     return FD_TYPE_DEFAULT;
201 }
202
203 static struct named_pipe *create_named_pipe( const WCHAR *name, size_t len )
204 {
205     struct named_pipe *pipe;
206
207     if ((pipe = create_named_object( &named_pipe_ops, name, len )))
208     {
209         if (get_error() != STATUS_OBJECT_NAME_COLLISION)
210         {
211             /* initialize it if it didn't already exist */
212             pipe->users = 0;
213         }
214     }
215     return pipe;
216 }
217
218 static struct pipe_user *get_pipe_user_obj( struct process *process, handle_t handle,
219                                             unsigned int access )
220 {
221     return (struct pipe_user *)get_handle_obj( process, handle, access, &pipe_user_ops );
222 }
223
224 static struct pipe_user *create_pipe_user( struct named_pipe *pipe, int fd )
225 {
226     struct pipe_user *user;
227
228     user = alloc_object( &pipe_user_ops, fd );
229     if(!user)
230         return NULL;
231
232     user->pipe = pipe;
233     user->state = ps_none;
234     user->other = NULL;
235     user->thread = NULL;
236     user->func = NULL;
237     user->overlapped = NULL;
238
239     /* add to list of pipe users */
240     if ((user->next = pipe->users)) user->next->prev = user;
241     user->prev = NULL;
242     pipe->users = user;
243
244     grab_object(pipe);
245
246     return user;
247 }
248
249 static struct pipe_user *find_partner(struct named_pipe *pipe, enum pipe_state state)
250 {
251     struct pipe_user *x;
252
253     for(x = pipe->users; x; x=x->next)
254     {
255         if(x->state==state)
256         break;
257     }
258
259     if(!x)
260         return NULL;
261
262     return (struct pipe_user *)grab_object( x );
263 }
264
265 DECL_HANDLER(create_named_pipe)
266 {
267     struct named_pipe *pipe;
268     struct pipe_user *user;
269
270     reply->handle = 0;
271     pipe = create_named_pipe( get_req_data(), get_req_data_size() );
272     if(!pipe)
273         return;
274
275     if (get_error() != STATUS_OBJECT_NAME_COLLISION)
276     {
277         pipe->insize = req->insize;
278         pipe->outsize = req->outsize;
279         pipe->maxinstances = req->maxinstances;
280         pipe->timeout = req->timeout;
281         pipe->pipemode = req->pipemode;
282     }
283
284     user = create_pipe_user (pipe, -1);
285
286     if(user)
287     {
288         user->state = ps_idle_server;
289         reply->handle = alloc_handle( current->process, user, GENERIC_READ|GENERIC_WRITE, 0 );
290         release_object( user );
291     }
292
293     release_object( pipe );
294 }
295
296 DECL_HANDLER(open_named_pipe)
297 {
298     struct named_pipe *pipe;
299
300     reply->handle = 0;
301     pipe = create_named_pipe( get_req_data(), get_req_data_size() );
302     if(!pipe)
303         return;
304
305     if (get_error() == STATUS_OBJECT_NAME_COLLISION)
306     {
307         struct pipe_user *partner;
308
309         if ((partner = find_partner(pipe, ps_wait_open)))
310         {
311             int fds[2];
312
313             if(!socketpair(PF_UNIX, SOCK_STREAM, 0, fds))
314             {
315                 struct pipe_user *user;
316
317                 if( (user = create_pipe_user (pipe, fds[1])) )
318                 {
319                     partner->obj.fd = fds[0];
320                     notify_waiter(partner,STATUS_SUCCESS);
321                     partner->state = ps_connected_server;
322                     partner->other = user;
323                     user->state = ps_connected_client;
324                     user->other = partner;
325                     reply->handle = alloc_handle( current->process, user, req->access, 0 );
326                     release_object(user);
327                 }
328                 else
329                 {
330                     close(fds[0]);
331                 }
332             }
333             release_object( partner );
334         }
335         else
336         {
337             set_error(STATUS_PIPE_NOT_AVAILABLE);
338         }
339     }
340     else
341     {
342         set_error(STATUS_NO_SUCH_FILE);
343     }
344
345     release_object(pipe);
346 }
347
348 DECL_HANDLER(connect_named_pipe)
349 {
350     struct pipe_user *user, *partner;
351
352     user = get_pipe_user_obj(current->process, req->handle, 0);
353     if(!user)
354         return;
355
356     if( user->state != ps_idle_server )
357     {
358         set_error(STATUS_PORT_ALREADY_SET);
359     }
360     else
361     {
362         user->state = ps_wait_open;
363         user->thread = current;
364         user->func = req->func;
365         user->overlapped = req->overlapped;
366
367         /* notify all waiters that a pipe just became available */
368         while( (partner = find_partner(user->pipe,ps_wait_connect)) )
369         {
370             notify_waiter(partner,STATUS_SUCCESS);
371             release_object(partner);
372             release_object(partner);
373         }
374     }
375
376     release_object(user);
377 }
378
379 DECL_HANDLER(wait_named_pipe)
380 {
381     struct named_pipe *pipe;
382
383     pipe = create_named_pipe( get_req_data(), get_req_data_size() );
384     if( pipe )
385     {
386         /* only wait if the pipe already exists */
387         if(get_error() == STATUS_OBJECT_NAME_COLLISION)
388         {
389             struct pipe_user *partner;
390
391             set_error(STATUS_SUCCESS);
392             if( (partner = find_partner(pipe,ps_wait_open)) )
393             {
394                 /* this should use notify_waiter, 
395                    but no pipe_user object exists now... */
396                 thread_queue_apc(current,NULL,req->func,
397                     APC_ASYNC,1,2,req->overlapped,STATUS_SUCCESS);
398                 release_object(partner);
399             }
400             else
401             {
402                 struct pipe_user *user;
403
404                 if( (user = create_pipe_user (pipe, -1)) )
405                 {
406                     user->state = ps_wait_connect;
407                     user->thread = current;
408                     user->func = req->func;
409                     user->overlapped = req->overlapped;
410                     /* don't release it */
411                 }
412             }
413         }
414         else
415         {
416             set_error(STATUS_PIPE_NOT_AVAILABLE);
417         }
418         release_object(pipe);
419     }
420 }
421
422 DECL_HANDLER(disconnect_named_pipe)
423 {
424     struct pipe_user *user;
425
426     user = get_pipe_user_obj(current->process, req->handle, 0);
427     if(!user)
428         return;
429     if( (user->state == ps_connected_server) &&
430         (user->other->state == ps_connected_client) )
431     {
432         close(user->other->obj.fd);
433         user->other->obj.fd = -1;
434         user->other->state = ps_disconnected;
435         user->other->other = NULL;
436
437         close(user->obj.fd);
438         user->obj.fd = -1;
439         user->state = ps_idle_server;
440         user->other = NULL;
441     }
442     release_object(user);
443 }
444
445 DECL_HANDLER(get_named_pipe_info)
446 {
447     struct pipe_user *user;
448
449     user = get_pipe_user_obj(current->process, req->handle, 0);
450     if(!user)
451         return;
452
453     reply->flags        = user->pipe->pipemode;
454     reply->maxinstances = user->pipe->maxinstances;
455     reply->insize       = user->pipe->insize;
456     reply->outsize      = user->pipe->outsize;
457
458     release_object(user);
459 }
460