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