fwrite: fixed handling of already buffered data.
[wine.git] / server / named_pipe.c
blob86c37aa545458fa251c94fdde7d2ce322a1e64b9
1 /*
2 * Server-side pipe management
4 * Copyright (C) 1998 Alexandre Julliard
5 * Copyright (C) 2001 Mike McCormack
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.
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.
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
21 * TODO:
22 * improve error handling
25 #include "config.h"
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>
38 #include "winbase.h"
40 #include "handle.h"
41 #include "thread.h"
42 #include "request.h"
44 enum pipe_state
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
55 struct named_pipe;
57 struct pipe_user
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;
70 struct named_pipe
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;
81 static void named_pipe_dump( struct object *obj, int verbose );
82 static void named_pipe_destroy( struct object *obj);
84 static const struct object_ops named_pipe_ops =
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 */
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 );
106 static const struct object_ops pipe_user_ops =
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 */
123 static void named_pipe_dump( struct object *obj, int verbose )
125 struct named_pipe *pipe = (struct named_pipe *)obj;
126 assert( obj->ops == &named_pipe_ops );
127 fprintf( stderr, "named pipe %p\n" ,pipe);
130 static void pipe_user_dump( struct object *obj, int verbose )
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 );
137 static void named_pipe_destroy( struct object *obj)
139 struct named_pipe *pipe = (struct named_pipe *)obj;
140 assert( !pipe->users );
143 static void notify_waiter( struct pipe_user *user, unsigned int status)
145 if(user->thread && user->func && user->overlapped)
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);
151 if (user->thread) release_object(user->thread);
152 user->thread = NULL;
153 user->func = NULL;
154 user->overlapped=NULL;
157 static void pipe_user_destroy( struct object *obj)
159 struct pipe_user *user = (struct pipe_user *)obj;
161 assert( obj->ops == &pipe_user_ops );
163 if(user->overlapped)
164 notify_waiter(user,STATUS_HANDLES_CLOSED);
166 if(user->other)
168 close(user->other->obj.fd);
169 user->other->obj.fd = -1;
170 switch(user->other->state)
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);
182 user->other->other=NULL;
183 user->other = NULL;
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);
194 static int pipe_user_get_fd( struct object *obj )
196 struct pipe_user *user = (struct pipe_user *)obj;
197 assert( obj->ops == &pipe_user_ops );
198 return user->obj.fd;
201 static int pipe_user_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags )
203 if (reply)
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;
216 *flags = 0;
217 return FD_TYPE_DEFAULT;
220 static struct named_pipe *create_named_pipe( const WCHAR *name, size_t len )
222 struct named_pipe *pipe;
224 if ((pipe = create_named_object( &named_pipe_ops, name, len )))
226 if (get_error() != STATUS_OBJECT_NAME_COLLISION)
228 /* initialize it if it didn't already exist */
229 pipe->users = 0;
232 return pipe;
235 static struct pipe_user *get_pipe_user_obj( struct process *process, handle_t handle,
236 unsigned int access )
238 return (struct pipe_user *)get_handle_obj( process, handle, access, &pipe_user_ops );
241 static struct pipe_user *create_pipe_user( struct named_pipe *pipe, int fd )
243 struct pipe_user *user;
245 user = alloc_object( &pipe_user_ops, fd );
246 if(!user)
247 return NULL;
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;
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;
261 grab_object(pipe);
263 return user;
266 static struct pipe_user *find_partner(struct named_pipe *pipe, enum pipe_state state)
268 struct pipe_user *x;
270 for(x = pipe->users; x; x=x->next)
272 if(x->state==state)
273 break;
276 if(!x)
277 return NULL;
279 return (struct pipe_user *)grab_object( x );
282 DECL_HANDLER(create_named_pipe)
284 struct named_pipe *pipe;
285 struct pipe_user *user;
287 reply->handle = 0;
288 pipe = create_named_pipe( get_req_data(), get_req_data_size() );
289 if(!pipe)
290 return;
292 if (get_error() != STATUS_OBJECT_NAME_COLLISION)
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;
301 user = create_pipe_user (pipe, -1);
303 if(user)
305 user->state = ps_idle_server;
306 reply->handle = alloc_handle( current->process, user, GENERIC_READ|GENERIC_WRITE, 0 );
307 release_object( user );
310 release_object( pipe );
313 DECL_HANDLER(open_named_pipe)
315 struct named_pipe *pipe;
317 reply->handle = 0;
318 pipe = create_named_pipe( get_req_data(), get_req_data_size() );
319 if(!pipe)
320 return;
322 if (get_error() == STATUS_OBJECT_NAME_COLLISION)
324 struct pipe_user *partner;
326 if ((partner = find_partner(pipe, ps_wait_open)))
328 int fds[2];
330 if(!socketpair(PF_UNIX, SOCK_STREAM, 0, fds))
332 struct pipe_user *user;
334 if( (user = create_pipe_user (pipe, fds[1])) )
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);
345 else
347 close(fds[0]);
350 release_object( partner );
352 else
354 set_error(STATUS_PIPE_NOT_AVAILABLE);
357 else
359 set_error(STATUS_NO_SUCH_FILE);
362 release_object(pipe);
365 DECL_HANDLER(connect_named_pipe)
367 struct pipe_user *user, *partner;
369 user = get_pipe_user_obj(current->process, req->handle, 0);
370 if(!user)
371 return;
373 if( user->state != ps_idle_server )
375 set_error(STATUS_PORT_ALREADY_SET);
377 else
379 user->state = ps_wait_open;
380 user->thread = (struct thread *)grab_object(current);
381 user->func = req->func;
382 user->overlapped = req->overlapped;
384 /* notify all waiters that a pipe just became available */
385 while( (partner = find_partner(user->pipe,ps_wait_connect)) )
387 notify_waiter(partner,STATUS_SUCCESS);
388 release_object(partner);
389 release_object(partner);
393 release_object(user);
396 DECL_HANDLER(wait_named_pipe)
398 struct named_pipe *pipe;
400 pipe = create_named_pipe( get_req_data(), get_req_data_size() );
401 if( pipe )
403 /* only wait if the pipe already exists */
404 if(get_error() == STATUS_OBJECT_NAME_COLLISION)
406 struct pipe_user *partner;
408 set_error(STATUS_SUCCESS);
409 if( (partner = find_partner(pipe,ps_wait_open)) )
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);
417 else
419 struct pipe_user *user;
421 if( (user = create_pipe_user (pipe, -1)) )
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 */
431 else
433 set_error(STATUS_PIPE_NOT_AVAILABLE);
435 release_object(pipe);
439 DECL_HANDLER(disconnect_named_pipe)
441 struct pipe_user *user;
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) )
449 close(user->other->obj.fd);
450 user->other->obj.fd = -1;
451 user->other->state = ps_disconnected;
452 user->other->other = NULL;
454 close(user->obj.fd);
455 user->obj.fd = -1;
456 user->state = ps_idle_server;
457 user->other = NULL;
459 release_object(user);
462 DECL_HANDLER(get_named_pipe_info)
464 struct pipe_user *user;
466 user = get_pipe_user_obj(current->process, req->handle, 0);
467 if(!user)
468 return;
470 reply->flags = user->pipe->pipemode;
471 reply->maxinstances = user->pipe->maxinstances;
472 reply->insize = user->pipe->insize;
473 reply->outsize = user->pipe->outsize;
475 release_object(user);