Be more strict and verbose while testing
[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 "winternl.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     int                 read_timeout;
60     struct list         writers;
61 };
62
63 /* mailslot functions */
64 static void mailslot_dump( struct object*, int );
65 static struct fd *mailslot_get_fd( struct object * );
66 static void mailslot_destroy( struct object * );
67
68 static const struct object_ops mailslot_ops =
69 {
70     sizeof(struct mailslot),   /* size */
71     mailslot_dump,             /* dump */
72     default_fd_add_queue,      /* add_queue */
73     default_fd_remove_queue,   /* remove_queue */
74     default_fd_signaled,       /* signaled */
75     no_satisfied,              /* satisfied */
76     no_signal,                 /* signal */
77     mailslot_get_fd,           /* get_fd */
78     no_lookup_name,            /* lookup_name */
79     no_close_handle,           /* close_handle */
80     mailslot_destroy           /* destroy */
81 };
82
83 static int mailslot_get_info( struct fd * );
84 static void mailslot_queue_async( struct fd *, void*, void*, void*, int, int );
85
86 static const struct fd_ops mailslot_fd_ops =
87 {
88     default_fd_get_poll_events, /* get_poll_events */
89     default_poll_event,         /* poll_event */
90     no_flush,                   /* flush */
91     mailslot_get_info,          /* get_file_info */
92     mailslot_queue_async,       /* queue_async */
93     default_fd_cancel_async     /* cancel_async */
94 };
95
96 struct mail_writer
97 {
98     struct object         obj;
99     struct mailslot      *mailslot;
100     struct list           entry;
101     int                   access;
102     int                   sharing;
103 };
104
105 static void mail_writer_dump( struct object *obj, int verbose );
106 static struct fd *mail_writer_get_fd( struct object *obj );
107 static void mail_writer_destroy( struct object *obj);
108
109 static const struct object_ops mail_writer_ops =
110 {
111     sizeof(struct mail_writer), /* size */
112     mail_writer_dump,           /* dump */
113     no_add_queue,               /* add_queue */
114     NULL,                       /* remove_queue */
115     NULL,                       /* signaled */
116     NULL,                       /* satisfied */
117     no_signal,                  /* signal */
118     mail_writer_get_fd,         /* get_fd */
119     no_lookup_name,             /* lookup_name */
120     no_close_handle,            /* close_handle */
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     release_object( mailslot->fd );
144     release_object( mailslot->write_fd );
145 }
146
147 static void mailslot_dump( struct object *obj, int verbose )
148 {
149     struct mailslot *mailslot = (struct mailslot *) obj;
150
151     assert( obj->ops == &mailslot_ops );
152     fprintf( stderr, "Mailslot max_msgsize=%d read_timeout=%d\n",
153              mailslot->max_msgsize, mailslot->read_timeout );
154 }
155
156 static int mailslot_message_count(struct mailslot *mailslot)
157 {
158     struct pollfd pfd;
159
160     /* poll the socket to see if there's any messages */
161     pfd.fd = get_unix_fd( mailslot->fd );
162     pfd.events = POLLIN;
163     pfd.revents = 0;
164     return (poll( &pfd, 1, 0 ) == 1) ? 1 : 0;
165 }
166
167 static int mailslot_next_msg_size( struct mailslot *mailslot )
168 {
169     int size, fd;
170
171     size = 0;
172     fd = get_unix_fd( mailslot->fd );
173     ioctl( fd, FIONREAD, &size );
174     return size;
175 }
176
177 static int mailslot_get_info( struct fd *fd )
178 {
179     struct mailslot *mailslot = get_fd_user( fd );
180     assert( mailslot->obj.ops == &mailslot_ops );
181     return FD_FLAG_TIMEOUT | FD_FLAG_AVAILABLE;
182 }
183
184 static struct fd *mailslot_get_fd( struct object *obj )
185 {
186     struct mailslot *mailslot = (struct mailslot *) obj;
187
188     return (struct fd *)grab_object( mailslot->fd );
189 }
190
191 static void mailslot_queue_async( struct fd *fd, void *apc, void *user,
192                                   void *iosb, int type, int count )
193 {
194     struct mailslot *mailslot = get_fd_user( fd );
195     int *timeout = NULL;
196
197     assert(mailslot->obj.ops == &mailslot_ops);
198
199     if (type != ASYNC_TYPE_READ)
200     {
201         set_error(STATUS_INVALID_PARAMETER);
202         return;
203     }
204
205     if (list_empty( &mailslot->writers ) ||
206         !mailslot_message_count( mailslot ))
207     {
208         set_error(STATUS_IO_TIMEOUT);
209         return;
210     }
211
212     if (mailslot->read_timeout != -1) timeout = &mailslot->read_timeout;
213
214     fd_queue_async_timeout( fd, apc, user, iosb, type, count, timeout );
215 }
216
217 static struct mailslot *create_mailslot( const struct unicode_str *name, unsigned int attr,
218                                          int max_msgsize, int read_timeout )
219 {
220     struct mailslot *mailslot;
221     int fds[2];
222     static const WCHAR slot[] = {'m','a','i','l','s','l','o','t','\\'};
223
224     if ((name->len <= sizeof(slot)) || strncmpiW( slot, name->str, sizeof(slot)/sizeof(WCHAR) ))
225     {
226         set_error( STATUS_OBJECT_NAME_INVALID );
227         return NULL;
228     }
229
230     mailslot = create_named_object( sync_namespace, &mailslot_ops, name, attr );
231     if (!mailslot)
232         return NULL;
233
234     /* it already exists - there can only be one mailslot to read from */
235     if (get_error() == STATUS_OBJECT_NAME_EXISTS)
236     {
237         release_object( mailslot );
238         return NULL;
239     }
240
241     mailslot->fd = NULL;
242     mailslot->write_fd = NULL;
243     mailslot->max_msgsize = max_msgsize;
244     mailslot->read_timeout = read_timeout;
245     list_init( &mailslot->writers );
246
247     if (!socketpair( PF_UNIX, SOCK_DGRAM, 0, fds ))
248     {
249         fcntl( fds[0], F_SETFL, O_NONBLOCK );
250         fcntl( fds[1], F_SETFL, O_NONBLOCK );
251         mailslot->fd = create_anonymous_fd( &mailslot_fd_ops,
252                                 fds[1], &mailslot->obj );
253         mailslot->write_fd = create_anonymous_fd( &mail_writer_fd_ops,
254                                 fds[0], &mailslot->obj );
255         if (mailslot->fd && mailslot->write_fd) return mailslot;
256     }
257     else file_set_error();
258
259     release_object( mailslot );
260     return NULL;
261 }
262
263 static struct mailslot *open_mailslot( const struct unicode_str *name, unsigned int attr )
264 {
265     struct object *obj;
266
267     obj = find_object( sync_namespace, name, attr );
268     if (obj)
269     {
270         if (obj->ops == &mailslot_ops)
271             return (struct mailslot *)obj;
272         release_object( obj );
273         set_error( STATUS_OBJECT_TYPE_MISMATCH );
274     }
275     else
276         set_error( STATUS_OBJECT_NAME_NOT_FOUND );
277
278     return NULL;
279 }
280
281 static void mail_writer_dump( struct object *obj, int verbose )
282 {
283     fprintf( stderr, "Mailslot writer\n" );
284 }
285
286 static void mail_writer_destroy( struct object *obj)
287 {
288     struct mail_writer *writer = (struct mail_writer *) obj;
289
290     list_remove( &writer->entry );
291     release_object( writer->mailslot );
292 }
293
294 static int mail_writer_get_info( struct fd *fd )
295 {
296     return 0;
297 }
298
299 static struct fd *mail_writer_get_fd( struct object *obj )
300 {
301     struct mail_writer *writer = (struct mail_writer *) obj;
302
303     return (struct fd *)grab_object( writer->mailslot->write_fd );
304 }
305
306 /*
307  * Readers and writers cannot be mixed.
308  * If there's more than one writer, all writers must open with FILE_SHARE_WRITE
309  */
310 static struct mail_writer *create_mail_writer( struct mailslot *mailslot, unsigned int access,
311                                                unsigned int sharing )
312 {
313     struct mail_writer *writer;
314
315     if (!list_empty( &mailslot->writers ))
316     {
317         writer = LIST_ENTRY( list_head(&mailslot->writers), struct mail_writer, entry );
318
319         if (((access & GENERIC_WRITE) || (writer->access & GENERIC_WRITE)) &&
320            !((sharing & FILE_SHARE_WRITE) && (writer->sharing & FILE_SHARE_WRITE)))
321         {
322             set_error( STATUS_SHARING_VIOLATION );
323             return NULL;
324         }
325     }
326
327     writer = alloc_object( &mail_writer_ops );
328     if (!writer)
329         return NULL;
330
331     grab_object( mailslot );
332     writer->mailslot = mailslot;
333     writer->access = access;
334     writer->sharing = sharing;
335
336     list_add_head( &mailslot->writers, &writer->entry );
337
338     return writer;
339 }
340
341 static struct mailslot *get_mailslot_obj( struct process *process, obj_handle_t handle,
342                                           unsigned int access )
343 {
344     struct object *obj;
345     obj = get_handle_obj( process, handle, access, &mailslot_ops );
346     return (struct mailslot *) obj;
347 }
348
349
350 /* create a mailslot */
351 DECL_HANDLER(create_mailslot)
352 {
353     struct mailslot *mailslot;
354     struct unicode_str name;
355
356     reply->handle = 0;
357     get_req_unicode_str( &name );
358     mailslot = create_mailslot( &name, req->attributes, req->max_msgsize, req->read_timeout );
359     if (mailslot)
360     {
361         reply->handle = alloc_handle( current->process, mailslot,
362                                       req->access, req->attributes & OBJ_INHERIT );
363         release_object( mailslot );
364     }
365 }
366
367
368 /* open an existing mailslot */
369 DECL_HANDLER(open_mailslot)
370 {
371     struct mailslot *mailslot;
372     struct unicode_str name;
373
374     reply->handle = 0;
375     get_req_unicode_str( &name );
376
377     if (!(req->sharing & FILE_SHARE_READ))
378     {
379         set_error( STATUS_SHARING_VIOLATION );
380         return;
381     }
382
383     mailslot = open_mailslot( &name, req->attributes );
384     if (mailslot)
385     {
386         struct mail_writer *writer;
387
388         writer = create_mail_writer( mailslot, req->access, req->sharing );
389         if (writer)
390         {
391             reply->handle = alloc_handle( current->process, writer,
392                                           req->access, req->attributes & OBJ_INHERIT );
393             release_object( writer );
394         }
395         release_object( mailslot );
396     }
397     else
398         set_error( STATUS_NO_SUCH_FILE );
399 }
400
401
402 /* set mailslot information */
403 DECL_HANDLER(set_mailslot_info)
404 {
405     struct mailslot *mailslot = get_mailslot_obj( current->process, req->handle, 0 );
406
407     if (mailslot)
408     {
409         if (req->flags & MAILSLOT_SET_READ_TIMEOUT)
410             mailslot->read_timeout = req->read_timeout;
411         reply->max_msgsize = mailslot->max_msgsize;
412         reply->read_timeout = mailslot->read_timeout;
413         reply->msg_count = mailslot_message_count(mailslot);
414
415         /* get the size of the next message */
416         if (reply->msg_count)
417             reply->next_msgsize = mailslot_next_msg_size(mailslot);
418         else
419             reply->next_msgsize = MAILSLOT_NO_MESSAGE;
420
421         release_object( mailslot );
422     }
423 }