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