Implement NtAccessCheck.
[wine] / server / mailslot.c
1 /*
2  * Server-side mailslot management
3  *
4  * Copyright (C) 1998 Alexandre Julliard
5  * Copyright (C) 2005 Mike McCormack
6  *
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.
11  *
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.
16  *
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
20  *
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25 #include "wine/unicode.h"
26
27 #include <assert.h>
28 #include <fcntl.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <sys/time.h>
34 #include <sys/types.h>
35
36 #ifdef HAVE_SYS_IOCTL_H
37 #include <sys/ioctl.h>
38 #endif
39 #ifdef HAVE_SYS_SOCKET_H
40 #include <sys/socket.h>
41 #endif
42 #ifdef HAVE_SYS_FILIO_H
43 #include <sys/filio.h>
44 #endif
45 #include "windef.h"
46 #include "winbase.h"
47
48 #include "file.h"
49 #include "handle.h"
50 #include "thread.h"
51 #include "request.h"
52
53 struct mailslot
54 {
55     struct object       obj;
56     struct fd          *fd;
57     struct fd          *write_fd;
58     unsigned int        max_msgsize;
59     unsigned int        read_timeout;
60     struct list         writers;
61     struct list         read_q;
62 };
63
64 /* mailslot functions */
65 static void mailslot_dump( struct object*, int );
66 static struct fd *mailslot_get_fd( struct object * );
67 static void mailslot_destroy( struct object * );
68
69 static const struct object_ops mailslot_ops =
70 {
71     sizeof(struct mailslot),   /* size */
72     mailslot_dump,             /* dump */
73     default_fd_add_queue,      /* add_queue */
74     default_fd_remove_queue,   /* remove_queue */
75     default_fd_signaled,       /* signaled */
76     no_satisfied,              /* satisfied */
77     no_signal,                 /* signal */
78     mailslot_get_fd,           /* get_fd */
79     mailslot_destroy           /* destroy */
80 };
81
82 static int mailslot_get_poll_events( struct fd * );
83 static void mailslot_poll_event( struct fd *, int );
84 static int mailslot_get_info( struct fd * );
85 static void mailslot_queue_async( struct fd *, void*, void*, void*, int, int );
86 static void mailslot_cancel_async( struct fd * );
87
88 static const struct fd_ops mailslot_fd_ops =
89 {
90     mailslot_get_poll_events,  /* get_poll_events */
91     mailslot_poll_event,       /* poll_event */
92     no_flush,                  /* flush */
93     mailslot_get_info,         /* get_file_info */
94     mailslot_queue_async,      /* queue_async */
95     mailslot_cancel_async      /* cancel_async */
96 };
97
98 struct mail_writer
99 {
100     struct object         obj;
101     struct mailslot      *mailslot;
102     struct list           entry;
103     int                   access;
104     int                   sharing;
105 };
106
107 static void mail_writer_dump( struct object *obj, int verbose );
108 static struct fd *mail_writer_get_fd( struct object *obj );
109 static void mail_writer_destroy( struct object *obj);
110
111 static const struct object_ops mail_writer_ops =
112 {
113     sizeof(struct mail_writer), /* size */
114     mail_writer_dump,           /* dump */
115     no_add_queue,               /* add_queue */
116     NULL,                       /* remove_queue */
117     NULL,                       /* signaled */
118     NULL,                       /* satisfied */
119     no_signal,                  /* signal */
120     mail_writer_get_fd,         /* get_fd */
121     mail_writer_destroy         /* destroy */
122 };
123
124 static int mail_writer_get_info( struct fd *fd );
125
126 static const struct fd_ops mail_writer_fd_ops =
127 {
128     NULL,                        /* get_poll_events */
129     NULL,                        /* poll_event */
130     no_flush,                    /* flush */
131     mail_writer_get_info,        /* get_file_info */
132     no_queue_async,              /* queue_async */
133     NULL                         /* cancel_async */
134 };
135
136 static void mailslot_destroy( struct object *obj)
137 {
138     struct mailslot *mailslot = (struct mailslot *) obj;
139
140     assert( mailslot->fd );
141     assert( mailslot->write_fd );
142
143     async_terminate_queue( &mailslot->read_q, STATUS_CANCELLED );
144
145     release_object( mailslot->fd );
146     release_object( mailslot->write_fd );
147 }
148
149 static void mailslot_dump( struct object *obj, int verbose )
150 {
151     struct mailslot *mailslot = (struct mailslot *) obj;
152
153     assert( obj->ops == &mailslot_ops );
154     fprintf( stderr, "Mailslot max_msgsize=%d read_timeout=%d\n",
155              mailslot->max_msgsize, mailslot->read_timeout );
156 }
157
158 static int mailslot_message_count(struct mailslot *mailslot)
159 {
160     struct pollfd pfd;
161
162     /* poll the socket to see if there's any messages */
163     pfd.fd = get_unix_fd( mailslot->fd );
164     pfd.events = POLLIN;
165     pfd.revents = 0;
166     return (poll( &pfd, 1, 0 ) == 1) ? 1 : 0;
167 }
168
169 static int mailslot_next_msg_size( struct mailslot *mailslot )
170 {
171     int size, fd;
172
173     size = 0;
174     fd = get_unix_fd( mailslot->fd );
175     ioctl( fd, FIONREAD, &size );
176     return size;
177 }
178
179 static int mailslot_get_info( struct fd *fd )
180 {
181     struct mailslot *mailslot = get_fd_user( fd );
182     assert( mailslot->obj.ops == &mailslot_ops );
183     return FD_FLAG_TIMEOUT | FD_FLAG_AVAILABLE;
184 }
185
186 static struct fd *mailslot_get_fd( struct object *obj )
187 {
188     struct mailslot *mailslot = (struct mailslot *) obj;
189
190     return (struct fd *)grab_object( mailslot->fd );
191 }
192
193 static int mailslot_get_poll_events( struct fd *fd )
194 {
195     struct mailslot *mailslot = get_fd_user( fd );
196     int events = 0;
197     assert( mailslot->obj.ops == &mailslot_ops );
198
199     if( !list_empty( &mailslot->read_q ))
200         events |= POLLIN;
201
202     return events;
203 }
204
205 static void mailslot_poll_event( struct fd *fd, int event )
206 {
207     struct mailslot *mailslot = get_fd_user( fd );
208
209     if( !list_empty( &mailslot->read_q ) && (POLLIN & event) )
210         async_terminate_head( &mailslot->read_q, STATUS_ALERTED );
211
212     set_fd_events( fd, mailslot_get_poll_events(fd) );
213 }
214
215 static void mailslot_queue_async( struct fd *fd, void *apc, void *user,
216                                   void *iosb, int type, int count )
217 {
218     struct mailslot *mailslot = get_fd_user( fd );
219     int events, *ptimeout = NULL;
220
221     assert(mailslot->obj.ops == &mailslot_ops);
222
223     if( type != ASYNC_TYPE_READ )
224     {
225         set_error(STATUS_INVALID_PARAMETER);
226         return;
227     }
228
229     if( list_empty( &mailslot->writers ) ||
230         !mailslot_message_count( mailslot ))
231     {
232         set_error(STATUS_IO_TIMEOUT);
233         return;
234     }
235
236     if (mailslot->read_timeout != MAILSLOT_WAIT_FOREVER)
237         ptimeout = &mailslot->read_timeout;
238
239     if (!create_async( current, ptimeout, &mailslot->read_q, apc, user, iosb ))
240         return;
241
242     /* Check if the new pending request can be served immediately */
243     events = check_fd_events( fd, mailslot_get_poll_events( fd ) );
244     if (events)
245     {
246         mailslot_poll_event( fd, events );
247         return;
248     }
249
250     set_fd_events( fd, mailslot_get_poll_events( fd ));
251 }
252
253 static void mailslot_cancel_async( struct fd *fd )
254 {
255     struct mailslot *mailslot = get_fd_user( fd );
256
257     assert(mailslot->obj.ops == &mailslot_ops);
258     async_terminate_queue( &mailslot->read_q, STATUS_CANCELLED );
259 }
260
261 static struct mailslot *create_mailslot( const WCHAR *name, size_t len, int max_msgsize,
262                                          int read_timeout )
263 {
264     struct mailslot *mailslot;
265     int fds[2];
266     static const WCHAR slot[] = {'m','a','i','l','s','l','o','t','\\',0};
267
268     if( ( len <= strlenW( slot ) ) || strncmpiW( slot, name, strlenW( slot ) ) )
269     {
270         set_error( STATUS_OBJECT_NAME_INVALID );
271         return NULL;
272     }
273
274     mailslot = create_named_object( sync_namespace, &mailslot_ops, name, len );
275     if( !mailslot )
276         return NULL;
277
278     /* it already exists - there can only be one mailslot to read from */
279     if( get_error() == STATUS_OBJECT_NAME_COLLISION )
280     {
281         release_object( mailslot );
282         return NULL;
283     }
284
285     mailslot->fd = NULL;
286     mailslot->write_fd = NULL;
287     mailslot->max_msgsize = max_msgsize;
288     mailslot->read_timeout = read_timeout;
289     list_init( &mailslot->writers );
290     list_init( &mailslot->read_q );
291
292     if( !socketpair( PF_UNIX, SOCK_DGRAM, 0, fds ) )
293     {
294         fcntl( fds[0], F_SETFL, O_NONBLOCK );
295         fcntl( fds[1], F_SETFL, O_NONBLOCK );
296         mailslot->fd = create_anonymous_fd( &mailslot_fd_ops,
297                                 fds[1], &mailslot->obj );
298         mailslot->write_fd = create_anonymous_fd( &mail_writer_fd_ops,
299                                 fds[0], &mailslot->obj );
300         if( mailslot->fd && mailslot->write_fd ) return mailslot;
301     }
302     else file_set_error();
303
304     release_object( mailslot );
305     return NULL;
306 }
307
308 static struct mailslot *open_mailslot( const WCHAR *name, size_t len )
309 {
310     struct object *obj;
311
312     obj = find_object( sync_namespace, name, len );
313     if (obj)
314     {
315         if (obj->ops == &mailslot_ops)
316             return (struct mailslot *)obj;
317         release_object( obj );
318         set_error( STATUS_OBJECT_TYPE_MISMATCH );
319     }
320     else
321         set_error( STATUS_OBJECT_NAME_NOT_FOUND );
322
323     return NULL;
324 }
325
326 static void mail_writer_dump( struct object *obj, int verbose )
327 {
328     fprintf( stderr, "Mailslot writer\n" );
329 }
330
331 static void mail_writer_destroy( struct object *obj)
332 {
333     struct mail_writer *writer = (struct mail_writer *) obj;
334
335     list_remove( &writer->entry );
336     release_object( writer->mailslot );
337 }
338
339 static int mail_writer_get_info( struct fd *fd )
340 {
341     return 0;
342 }
343
344 static struct fd *mail_writer_get_fd( struct object *obj )
345 {
346     struct mail_writer *writer = (struct mail_writer *) obj;
347
348     return (struct fd *)grab_object( writer->mailslot->write_fd );
349 }
350
351 /*
352  * Readers and writers cannot be mixed.
353  * If there's more than one writer, all writers must open with FILE_SHARE_WRITE
354  */
355 static struct mail_writer *create_mail_writer( struct mailslot *mailslot, unsigned int access,
356                                                unsigned int sharing )
357 {
358     struct mail_writer *writer;
359
360     if (!list_empty( &mailslot->writers ))
361     {
362         writer = LIST_ENTRY( list_head(&mailslot->writers), struct mail_writer, entry );
363
364         if (((access & GENERIC_WRITE) || (writer->access & GENERIC_WRITE)) &&
365            !((sharing & FILE_SHARE_WRITE) && (writer->sharing & FILE_SHARE_WRITE)))
366         {
367             set_error( STATUS_SHARING_VIOLATION );
368             return 0;
369         }
370     }
371
372     writer = alloc_object( &mail_writer_ops );
373     if (!writer)
374         return NULL;
375
376     grab_object( mailslot );
377     writer->mailslot = mailslot;
378     writer->access = access;
379     writer->sharing = sharing;
380
381     list_add_head( &mailslot->writers, &writer->entry );
382
383     return writer;
384 }
385
386 static struct mailslot *get_mailslot_obj( struct process *process, obj_handle_t handle,
387                                           unsigned int access )
388 {
389     struct object *obj;
390     obj = get_handle_obj( process, handle, access, &mailslot_ops );
391     return (struct mailslot *) obj;
392 }
393
394
395 /* create a mailslot */
396 DECL_HANDLER(create_mailslot)
397 {
398     struct mailslot *mailslot;
399
400     reply->handle = 0;
401     mailslot = create_mailslot( get_req_data(), get_req_data_size(),
402                                 req->max_msgsize, req->read_timeout );
403     if( mailslot )
404     {
405         reply->handle = alloc_handle( current->process, mailslot,
406                                       GENERIC_READ, req->inherit );
407         release_object( mailslot );
408     }
409 }
410
411
412 /* open an existing mailslot */
413 DECL_HANDLER(open_mailslot)
414 {
415     struct mailslot *mailslot;
416
417     reply->handle = 0;
418
419     if( ! ( req->sharing & FILE_SHARE_READ ) )
420     {
421         set_error( STATUS_SHARING_VIOLATION );
422         return;
423     }
424
425     mailslot = open_mailslot( get_req_data(), get_req_data_size() );
426     if( mailslot )
427     {
428         struct mail_writer *writer;
429
430         writer = create_mail_writer( mailslot, req->access, req->sharing );
431         if( writer )
432         {
433             reply->handle = alloc_handle( current->process, writer,
434                                           req->access, req->inherit );
435             release_object( writer );
436         }
437         release_object( mailslot );
438     }
439     else
440         set_error( STATUS_NO_SUCH_FILE );
441 }
442
443
444 /* set mailslot information */
445 DECL_HANDLER(set_mailslot_info)
446 {
447     struct mailslot *mailslot = get_mailslot_obj( current->process, req->handle, 0 );
448
449     if( mailslot )
450     {
451         if( req->flags & MAILSLOT_SET_READ_TIMEOUT )
452             mailslot->read_timeout = req->read_timeout;
453         reply->max_msgsize = mailslot->max_msgsize;
454         reply->read_timeout = mailslot->read_timeout;
455         reply->msg_count = mailslot_message_count(mailslot);
456
457         /* get the size of the next message */
458         if( reply->msg_count )
459             reply->next_msgsize = mailslot_next_msg_size(mailslot);
460         else
461             reply->next_msgsize = MAILSLOT_NO_MESSAGE;
462
463         release_object( mailslot );
464     }
465 }