From 2ab6a775bdd12461e4d01bae93658cbde08a10b8 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Wed, 30 Mar 2005 19:02:15 +0000 Subject: [PATCH] Implement mailslots. --- dlls/kernel/file.c | 4 +- dlls/kernel/sync.c | 45 +++- dlls/kernel/tests/mailslot.c | 46 +--- dlls/ntdll/file.c | 37 ++- include/wine/server_protocol.h | 62 ++++- server/Makefile.in | 1 + server/mailslot.c | 454 +++++++++++++++++++++++++++++++++ server/protocol.def | 36 +++ server/request.h | 6 + server/trace.c | 52 ++++ 10 files changed, 697 insertions(+), 46 deletions(-) create mode 100644 server/mailslot.c diff --git a/dlls/kernel/file.c b/dlls/kernel/file.c index 8ebdd22adbf..52428853590 100644 --- a/dlls/kernel/file.c +++ b/dlls/kernel/file.c @@ -1217,9 +1217,11 @@ HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing, if (!strncmpW(filename, bkslashes_with_dotW, 4)) { static const WCHAR pipeW[] = {'P','I','P','E','\\',0}; + static const WCHAR mailslotW[] = {'M','A','I','L','S','L','O','T','\\',0}; if ((isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0') || - !strncmpiW( filename + 4, pipeW, 5 )) + !strncmpiW( filename + 4, pipeW, 5 ) || + !strncmpiW( filename + 4, mailslotW, 9 )) { dosdev = 0; } diff --git a/dlls/kernel/sync.c b/dlls/kernel/sync.c index 4e4d4857747..bd4cc7213b2 100644 --- a/dlls/kernel/sync.c +++ b/dlls/kernel/sync.c @@ -1641,9 +1641,31 @@ BOOL WINAPI GetMailslotInfo( HANDLE hMailslot, LPDWORD lpMaxMessageSize, LPDWORD lpNextSize, LPDWORD lpMessageCount, LPDWORD lpReadTimeout ) { - FIXME("(%p): stub\n",hMailslot); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + BOOL r; + + TRACE("%p %p %p %p %p\n",hMailslot, + lpMaxMessageSize,lpNextSize,lpMessageCount,lpReadTimeout); + + SERVER_START_REQ( set_mailslot_info ) + { + req->handle = hMailslot; + req->flags = 0; + r = !wine_server_call_err( req ); + if( r ) + { + if( lpMaxMessageSize ) + *lpMaxMessageSize = reply->max_msgsize; + if( lpNextSize ) + *lpNextSize = reply->next_msgsize; + if( lpMessageCount ) + *lpMessageCount = reply->msg_count; + if( lpReadTimeout ) + *lpReadTimeout = reply->read_timeout; + } + } + SERVER_END_REQ; + + return r; } @@ -1662,9 +1684,20 @@ BOOL WINAPI GetMailslotInfo( HANDLE hMailslot, LPDWORD lpMaxMessageSize, */ BOOL WINAPI SetMailslotInfo( HANDLE hMailslot, DWORD dwReadTimeout) { - FIXME("%p %ld: stub\n", hMailslot, dwReadTimeout); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + BOOL r; + + TRACE("%p %ld\n", hMailslot, dwReadTimeout); + + SERVER_START_REQ( set_mailslot_info ) + { + req->handle = hMailslot; + req->flags = MAILSLOT_SET_READ_TIMEOUT; + req->read_timeout = dwReadTimeout; + r = !wine_server_call_err( req ); + } + SERVER_END_REQ; + + return r; } diff --git a/dlls/kernel/tests/mailslot.c b/dlls/kernel/tests/mailslot.c index 989ec532b70..735fea8f0d2 100644 --- a/dlls/kernel/tests/mailslot.c +++ b/dlls/kernel/tests/mailslot.c @@ -67,8 +67,6 @@ static int mailslot_test() ok( GetLastError() == ERROR_PATH_NOT_FOUND, "error should be ERROR_PATH_NOT_FOUND\n"); - todo_wine - { /* valid open, but with wacky parameters ... then check them */ hSlot = CreateMailslot( szmspath, -1, -1, NULL ); ok( hSlot != INVALID_HANDLE_VALUE , "mailslot with valid name failed\n"); @@ -77,22 +75,15 @@ static int mailslot_test() "getmailslotinfo failed\n"); ok( dwMax == ~0UL, "dwMax incorrect\n"); ok( dwNext == MAILSLOT_NO_MESSAGE, "dwNext incorrect\n"); - } ok( dwMsgCount == 0, "dwMsgCount incorrect\n"); - todo_wine - { ok( dwTimeout == ~0UL, "dwTimeout incorrect\n"); ok( GetMailslotInfo( hSlot, NULL, NULL, NULL, NULL ), "getmailslotinfo failed\n"); ok( CloseHandle(hSlot), "failed to close mailslot\n"); - } - todo_wine - { /* now open it for real */ hSlot = CreateMailslot( szmspath, 0, 0, NULL ); ok( hSlot != INVALID_HANDLE_VALUE , "valid mailslot failed\n"); - } /* try and read/write to it */ count = 0; @@ -106,8 +97,6 @@ static int mailslot_test() hWriter = CreateFile(szmspath, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); ok( hWriter == INVALID_HANDLE_VALUE, "bad sharing mode\n"); - todo_wine - { ok( GetLastError() == ERROR_SHARING_VIOLATION, "error should be ERROR_SHARING_VIOLATION\n"); @@ -115,7 +104,6 @@ static int mailslot_test() hWriter = CreateFile(szmspath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); ok( hWriter != INVALID_HANDLE_VALUE, "existing mailslot\n"); - } /* * opening a client should make no difference to @@ -132,11 +120,8 @@ static int mailslot_test() */ ok( !ReadFile( hWriter, buffer, sizeof buffer/2, &count, NULL), "can read client\n"); - todo_wine - { ok( WriteFile( hWriter, buffer, sizeof buffer/2, &count, NULL), "can't write client\n"); - } ok( !ReadFile( hWriter, buffer, sizeof buffer/2, &count, NULL), "can read client\n"); @@ -144,12 +129,9 @@ static int mailslot_test() * seeing as there's something in the slot, * we should be able to read it once */ - todo_wine - { ok( ReadFile( hSlot, buffer, sizeof buffer, &count, NULL), "slot read\n"); ok( count == (sizeof buffer/2), "short read\n" ); - } /* but not again */ ok( !ReadFile( hSlot, buffer, sizeof buffer, &count, NULL), @@ -174,8 +156,6 @@ static int mailslot_test() hSlot2 = CreateMailslot( szmspath, 0, 0, NULL ); ok( hSlot2 == INVALID_HANDLE_VALUE , "opened two mailslots\n"); - todo_wine - { /* close the client again */ ok( CloseHandle( hWriter ), "closing the client\n"); @@ -186,7 +166,6 @@ static int mailslot_test() hWriter = CreateFile(szmspath, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); ok( hWriter != INVALID_HANDLE_VALUE, "sharing writer\n"); - } /* * now try open another as a writer ... @@ -196,8 +175,6 @@ static int mailslot_test() FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); ok( hWriter2 == INVALID_HANDLE_VALUE, "greedy writer succeeded\n"); - todo_wine - { /* now try open another as a writer ... and share with the first */ hWriter2 = CreateFile(szmspath, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); @@ -208,7 +185,6 @@ static int mailslot_test() ok( GetMailslotInfo( hSlot, &dwMax, &dwNext, &dwMsgCount, &dwTimeout ), "getmailslotinfo failed\n"); ok( dwNext == MAILSLOT_NO_MESSAGE, "dwNext incorrect\n"); - } ok( dwMax == 0, "dwMax incorrect\n"); ok( dwMsgCount == 0, "dwMsgCount incorrect\n"); ok( dwTimeout == 0, "dwTimeout incorrect\n"); @@ -217,8 +193,6 @@ static int mailslot_test() ok( !ReadFile( hSlot, buffer, sizeof buffer, &count, NULL), "slot read\n"); /* write two messages */ - todo_wine - { buffer[0] = 'a'; ok( WriteFile( hWriter, buffer, 1, &count, NULL), "1st write failed\n"); @@ -226,7 +200,9 @@ static int mailslot_test() dwNext = dwMsgCount = 0; ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ), "getmailslotinfo failed\n"); + todo_wine { ok( dwNext == 1, "dwNext incorrect\n"); + } ok( dwMsgCount == 1, "dwMsgCount incorrect\n"); buffer[0] = 'b'; @@ -237,8 +213,10 @@ static int mailslot_test() dwNext = dwMsgCount = 0; ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ), "getmailslotinfo failed\n"); + todo_wine { ok( dwNext == 1, "dwNext incorrect\n"); ok( dwMsgCount == 2, "dwMsgCount incorrect\n"); + } /* write a 3rd message with zero size */ ok( WriteFile( hWriter2, buffer, 0, &count, NULL), "3rd write failed\n"); @@ -247,8 +225,10 @@ static int mailslot_test() dwNext = dwMsgCount = 0; ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ), "getmailslotinfo failed\n"); + todo_wine { ok( dwNext == 1, "dwNext incorrect\n"); ok( dwMsgCount == 3, "dwMsgCount incorrect\n"); + } buffer[0]=buffer[1]=0; @@ -265,8 +245,10 @@ static int mailslot_test() dwNext = dwMsgCount = 0; ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ), "getmailslotinfo failed\n"); + todo_wine { ok( dwNext == 2, "dwNext incorrect\n"); ok( dwMsgCount == 2, "dwMsgCount incorrect\n"); + } /* read the second message */ ok( ReadFile( hSlot, buffer, sizeof buffer, &count, NULL), @@ -278,13 +260,13 @@ static int mailslot_test() dwNext = dwMsgCount = 0; ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ), "getmailslotinfo failed\n"); - } + todo_wine { ok( dwNext == 0, "dwNext incorrect\n"); - todo_wine - { ok( dwMsgCount == 1, "dwMsgCount incorrect\n"); + } /* read the 3rd (zero length) message */ + todo_wine { ok( ReadFile( hSlot, buffer, sizeof buffer, &count, NULL), "3rd slot read failed\n"); } @@ -294,13 +276,10 @@ static int mailslot_test() * now there should be no more messages * check the mailslot info */ - todo_wine - { dwNext = dwMsgCount = 0; ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ), "getmailslotinfo failed\n"); ok( dwNext == MAILSLOT_NO_MESSAGE, "dwNext incorrect\n"); - } ok( dwMsgCount == 0, "dwMsgCount incorrect\n"); /* check that reads fail */ @@ -308,12 +287,9 @@ static int mailslot_test() "3rd slot read succeeded\n"); /* finally close the mailslot and its client */ - todo_wine - { ok( CloseHandle( hWriter2 ), "closing 2nd client\n"); ok( CloseHandle( hWriter ), "closing the client\n"); ok( CloseHandle( hSlot ), "closing the mailslot\n"); - } return 0; } diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index 30c3cbdc942..92c1bf64804 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -130,6 +130,7 @@ NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIB ULONG options, PVOID ea_buffer, ULONG ea_length ) { static const WCHAR pipeW[] = {'\\','?','?','\\','p','i','p','e','\\'}; + static const WCHAR mailslotW[] = {'\\','?','?','\\','M','A','I','L','S','L','O','T','\\'}; ANSI_STRING unix_name; int created = FALSE; @@ -166,6 +167,25 @@ NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIB return io->u.Status; } + /* check for mailslot */ + + if (attr->ObjectName->Length > sizeof(mailslotW) && + !memicmpW( attr->ObjectName->Buffer, mailslotW, sizeof(mailslotW)/sizeof(WCHAR) )) + { + SERVER_START_REQ( open_mailslot ) + { + req->access = access & GENERIC_WRITE; + req->sharing = sharing; + req->inherit = (attr->Attributes & OBJ_INHERIT) != 0; + wine_server_add_data( req, attr->ObjectName->Buffer + 4, + attr->ObjectName->Length - 4*sizeof(WCHAR) ); + io->u.Status = wine_server_call( req ); + *handle = reply->handle; + } + SERVER_END_REQ; + return io->u.Status; + } + io->u.Status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, disposition, !(attr->Attributes & OBJ_CASE_INSENSITIVE) ); @@ -1766,7 +1786,7 @@ NTSTATUS WINAPI NtCreateMailslotFile(PHANDLE pHandle, ULONG DesiredAccess, '\\','?','?','\\','M','A','I','L','S','L','O','T','\\'}; NTSTATUS ret; - FIXME("%p %08lx %p %p %08lx %08lx %08lx %p\n", + TRACE("%p %08lx %p %p %08lx %08lx %08lx %p\n", pHandle, DesiredAccess, attr, IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize, TimeOut); @@ -1777,7 +1797,18 @@ NTSTATUS WINAPI NtCreateMailslotFile(PHANDLE pHandle, ULONG DesiredAccess, return STATUS_OBJECT_NAME_INVALID; } - ret = STATUS_NOT_IMPLEMENTED; - + SERVER_START_REQ( create_mailslot ) + { + req->max_msgsize = MaxMessageSize; + req->read_timeout = TimeOut->QuadPart / -10000; + req->inherit = (attr->Attributes & OBJ_INHERIT) != 0; + wine_server_add_data( req, attr->ObjectName->Buffer + 4, + attr->ObjectName->Length - 4*sizeof(WCHAR) ); + ret = wine_server_call( req ); + if( ret == STATUS_SUCCESS ) + *pHandle = reply->handle; + } + SERVER_END_REQ; + return ret; } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 747c05b5455..e5d80ad3219 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -3241,6 +3241,57 @@ struct duplicate_token_reply }; + +struct create_mailslot_request +{ + struct request_header __header; + unsigned int max_msgsize; + unsigned int read_timeout; + int inherit; + /* VARARG(name,unicode_str); */ +}; +struct create_mailslot_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct open_mailslot_request +{ + struct request_header __header; + unsigned int access; + int inherit; + unsigned int sharing; + /* VARARG(name,unicode_str); */ +}; +struct open_mailslot_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct set_mailslot_info_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned int flags; + unsigned int read_timeout; +}; +struct set_mailslot_info_reply +{ + struct reply_header __header; + unsigned int max_msgsize; + unsigned int read_timeout; + unsigned int msg_count; + unsigned int next_msgsize; +}; +#define MAILSLOT_SET_READ_TIMEOUT 1 + + enum request { REQ_new_process, @@ -3428,6 +3479,9 @@ enum request REQ_adjust_token_privileges, REQ_get_token_privileges, REQ_duplicate_token, + REQ_create_mailslot, + REQ_open_mailslot, + REQ_set_mailslot_info, REQ_NB_REQUESTS }; @@ -3620,6 +3674,9 @@ union generic_request struct adjust_token_privileges_request adjust_token_privileges_request; struct get_token_privileges_request get_token_privileges_request; struct duplicate_token_request duplicate_token_request; + struct create_mailslot_request create_mailslot_request; + struct open_mailslot_request open_mailslot_request; + struct set_mailslot_info_request set_mailslot_info_request; }; union generic_reply { @@ -3810,8 +3867,11 @@ union generic_reply struct adjust_token_privileges_reply adjust_token_privileges_reply; struct get_token_privileges_reply get_token_privileges_reply; struct duplicate_token_reply duplicate_token_reply; + struct create_mailslot_reply create_mailslot_reply; + struct open_mailslot_reply open_mailslot_reply; + struct set_mailslot_info_reply set_mailslot_info_reply; }; -#define SERVER_PROTOCOL_VERSION 164 +#define SERVER_PROTOCOL_VERSION 165 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/Makefile.in b/server/Makefile.in index dd19f904ae6..17239a58880 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -21,6 +21,7 @@ C_SRCS = \ file.c \ handle.c \ hook.c \ + mailslot.c \ main.c \ mapping.c \ mutex.c \ diff --git a/server/mailslot.c b/server/mailslot.c new file mode 100644 index 00000000000..6d33371a541 --- /dev/null +++ b/server/mailslot.c @@ -0,0 +1,454 @@ +/* + * Server-side mailslot management + * + * Copyright (C) 1998 Alexandre Julliard + * Copyright (C) 2005 Mike McCormack + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "config.h" +#include "wine/port.h" +#include "wine/unicode.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#include "windef.h" +#include "winbase.h" + +#include "file.h" +#include "handle.h" +#include "thread.h" +#include "request.h" + +struct mailslot +{ + struct object obj; + struct fd *fd; + struct fd *write_fd; + unsigned int max_msgsize; + unsigned int read_timeout; + struct list writers; + struct list read_q; +}; + +/* mailslot functions */ +static void mailslot_dump( struct object*, int ); +static struct fd *mailslot_get_fd( struct object * ); +static void mailslot_destroy( struct object * ); + +static const struct object_ops mailslot_ops = +{ + sizeof(struct mailslot), /* size */ + mailslot_dump, /* dump */ + default_fd_add_queue, /* add_queue */ + default_fd_remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ + no_satisfied, /* satisfied */ + mailslot_get_fd, /* get_fd */ + mailslot_destroy /* destroy */ +}; + +static int mailslot_get_poll_events( struct fd * ); +static void mailslot_poll_event( struct fd *, int ); +static int mailslot_get_info( struct fd * ); +static void mailslot_queue_async( struct fd *, void*, void*, void*, int, int ); +static void mailslot_cancel_async( struct fd * ); + +static const struct fd_ops mailslot_fd_ops = +{ + mailslot_get_poll_events, /* get_poll_events */ + mailslot_poll_event, /* poll_event */ + no_flush, /* flush */ + mailslot_get_info, /* get_file_info */ + mailslot_queue_async, /* queue_async */ + mailslot_cancel_async /* cancel_async */ +}; + +struct mail_writer +{ + struct object obj; + struct mailslot *mailslot; + struct list entry; + int access; + int sharing; +}; + +static void mail_writer_dump( struct object *obj, int verbose ); +static struct fd *mail_writer_get_fd( struct object *obj ); +static void mail_writer_destroy( struct object *obj); + +static const struct object_ops mail_writer_ops = +{ + sizeof(struct mail_writer), /* size */ + mail_writer_dump, /* dump */ + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* satisfied */ + mail_writer_get_fd, /* get_fd */ + mail_writer_destroy /* destroy */ +}; + +static int mail_writer_get_info( struct fd *fd ); + +static const struct fd_ops mail_writer_fd_ops = +{ + NULL, /* get_poll_events */ + NULL, /* poll_event */ + no_flush, /* flush */ + mail_writer_get_info, /* get_file_info */ + no_queue_async, /* queue_async */ + NULL /* cancel_async */ +}; + +static void mailslot_destroy( struct object *obj) +{ + struct mailslot *mailslot = (struct mailslot *) obj; + + assert( mailslot->fd ); + assert( mailslot->write_fd ); + + async_terminate_queue( &mailslot->read_q, STATUS_CANCELLED ); + + release_object( mailslot->fd ); + release_object( mailslot->write_fd ); +} + +static void mailslot_dump( struct object *obj, int verbose ) +{ + struct mailslot *mailslot = (struct mailslot *) obj; + + assert( obj->ops == &mailslot_ops ); + fprintf( stderr, "Mailslot max_msgsize=%d read_timeout=%d\n", + mailslot->max_msgsize, mailslot->read_timeout ); +} + +static int mailslot_message_count(struct mailslot *mailslot) +{ + struct pollfd pfd; + + /* poll the socket to see if there's any messages */ + pfd.fd = get_unix_fd( mailslot->fd ); + pfd.events = POLLIN; + pfd.revents = 0; + return (poll( &pfd, 1, 0 ) == 1) ? 1 : 0; +} + +static int mailslot_get_info( struct fd *fd ) +{ + struct mailslot *mailslot = get_fd_user( fd ); + assert( mailslot->obj.ops == &mailslot_ops ); + return FD_FLAG_TIMEOUT | FD_FLAG_AVAILABLE; +} + +static struct fd *mailslot_get_fd( struct object *obj ) +{ + struct mailslot *mailslot = (struct mailslot *) obj; + + return (struct fd *)grab_object( mailslot->fd ); +} + +static int mailslot_get_poll_events( struct fd *fd ) +{ + struct mailslot *mailslot = get_fd_user( fd ); + int events = 0; + assert( mailslot->obj.ops == &mailslot_ops ); + + if( !list_empty( &mailslot->read_q )) + events |= POLLIN; + + return events; +} + +static void mailslot_poll_event( struct fd *fd, int event ) +{ + struct mailslot *mailslot = get_fd_user( fd ); + + if( !list_empty( &mailslot->read_q ) && (POLLIN & event) ) + async_terminate_head( &mailslot->read_q, STATUS_ALERTED ); + + set_fd_events( fd, mailslot_get_poll_events(fd) ); +} + +static void mailslot_queue_async( struct fd *fd, void *apc, void *user, + void *iosb, int type, int count ) +{ + struct mailslot *mailslot = get_fd_user( fd ); + int events, *ptimeout = NULL; + + assert(mailslot->obj.ops == &mailslot_ops); + + if( type != ASYNC_TYPE_READ ) + { + set_error(STATUS_INVALID_PARAMETER); + return; + } + + if( list_empty( &mailslot->writers ) || + !mailslot_message_count( mailslot )) + { + set_error(STATUS_IO_TIMEOUT); + return; + } + + if (mailslot->read_timeout != MAILSLOT_WAIT_FOREVER) + ptimeout = &mailslot->read_timeout; + + if (!create_async( current, ptimeout, &mailslot->read_q, apc, user, iosb )) + return; + + /* Check if the new pending request can be served immediately */ + events = check_fd_events( fd, mailslot_get_poll_events( fd ) ); + if (events) + { + mailslot_poll_event( fd, events ); + return; + } + + set_fd_events( fd, mailslot_get_poll_events( fd )); +} + +static void mailslot_cancel_async( struct fd *fd ) +{ + struct mailslot *mailslot = get_fd_user( fd ); + + assert(mailslot->obj.ops == &mailslot_ops); + async_terminate_queue( &mailslot->read_q, STATUS_CANCELLED ); +} + +static struct mailslot *create_mailslot( const WCHAR *name, size_t len, int max_msgsize, + int read_timeout ) +{ + struct mailslot *mailslot; + int fds[2]; + static const WCHAR slot[] = {'m','a','i','l','s','l','o','t','\\',0}; + + if( ( len <= strlenW( slot ) ) || strncmpiW( slot, name, strlenW( slot ) ) ) + { + set_error( STATUS_OBJECT_NAME_INVALID ); + return NULL; + } + + mailslot = create_named_object( sync_namespace, &mailslot_ops, name, len ); + if( !mailslot ) + return NULL; + + /* it already exists - there can only be one mailslot to read from */ + if( get_error() == STATUS_OBJECT_NAME_COLLISION ) + { + release_object( mailslot ); + return NULL; + } + + mailslot->fd = NULL; + mailslot->write_fd = NULL; + mailslot->max_msgsize = max_msgsize; + mailslot->read_timeout = read_timeout; + list_init( &mailslot->writers ); + list_init( &mailslot->read_q ); + + if( !socketpair( PF_UNIX, SOCK_DGRAM, 0, fds ) ) + { + fcntl( fds[0], F_SETFL, O_NONBLOCK ); + fcntl( fds[1], F_SETFL, O_NONBLOCK ); + mailslot->fd = create_anonymous_fd( &mailslot_fd_ops, + fds[1], &mailslot->obj ); + mailslot->write_fd = create_anonymous_fd( &mail_writer_fd_ops, + fds[0], &mailslot->obj ); + if( mailslot->fd && mailslot->write_fd ) return mailslot; + } + else file_set_error(); + + release_object( mailslot ); + return NULL; +} + +static struct mailslot *open_mailslot( const WCHAR *name, size_t len ) +{ + struct object *obj; + + obj = find_object( sync_namespace, name, len ); + if (obj) + { + if (obj->ops == &mailslot_ops) + return (struct mailslot *)obj; + release_object( obj ); + set_error( STATUS_OBJECT_TYPE_MISMATCH ); + } + else + set_error( STATUS_OBJECT_NAME_NOT_FOUND ); + + return NULL; +} + +static void mail_writer_dump( struct object *obj, int verbose ) +{ + fprintf( stderr, "Mailslot writer\n" ); +} + +static void mail_writer_destroy( struct object *obj) +{ + struct mail_writer *writer = (struct mail_writer *) obj; + + list_remove( &writer->entry ); + release_object( writer->mailslot ); +} + +static int mail_writer_get_info( struct fd *fd ) +{ + return 0; +} + +static struct fd *mail_writer_get_fd( struct object *obj ) +{ + struct mail_writer *writer = (struct mail_writer *) obj; + + return (struct fd *)grab_object( writer->mailslot->write_fd ); +} + +/* + * Readers and writers cannot be mixed. + * If there's more than one writer, all writers must open with FILE_SHARE_WRITE + */ +static struct mail_writer *create_mail_writer( struct mailslot *mailslot, unsigned int access, + unsigned int sharing ) +{ + struct mail_writer *writer; + + if (!list_empty( &mailslot->writers )) + { + writer = LIST_ENTRY( list_head(&mailslot->writers), struct mail_writer, entry ); + + if (((access & GENERIC_WRITE) || (writer->access & GENERIC_WRITE)) && + !((sharing & FILE_SHARE_WRITE) && (writer->sharing & FILE_SHARE_WRITE))) + { + set_error( STATUS_SHARING_VIOLATION ); + return 0; + } + } + + writer = alloc_object( &mail_writer_ops ); + if (!writer) + return NULL; + + grab_object( mailslot ); + writer->mailslot = mailslot; + writer->access = access; + writer->sharing = sharing; + + list_add_head( &mailslot->writers, &writer->entry ); + + return writer; +} + +static struct mailslot *get_mailslot_obj( struct process *process, obj_handle_t handle, + unsigned int access ) +{ + struct object *obj; + obj = get_handle_obj( process, handle, access, &mailslot_ops ); + return (struct mailslot *) obj; +} + + +/* create a mailslot */ +DECL_HANDLER(create_mailslot) +{ + struct mailslot *mailslot; + + reply->handle = 0; + mailslot = create_mailslot( get_req_data(), get_req_data_size(), + req->max_msgsize, req->read_timeout ); + if( mailslot ) + { + reply->handle = alloc_handle( current->process, mailslot, + GENERIC_READ, req->inherit ); + release_object( mailslot ); + } +} + + +/* open an existing mailslot */ +DECL_HANDLER(open_mailslot) +{ + struct mailslot *mailslot; + + reply->handle = 0; + + if( ! ( req->sharing & FILE_SHARE_READ ) ) + { + set_error( STATUS_SHARING_VIOLATION ); + return; + } + + mailslot = open_mailslot( get_req_data(), get_req_data_size() ); + if( mailslot ) + { + struct mail_writer *writer; + + writer = create_mail_writer( mailslot, req->access, req->sharing ); + if( writer ) + { + reply->handle = alloc_handle( current->process, writer, + req->access, req->inherit ); + release_object( writer ); + } + release_object( mailslot ); + } + else + set_error( STATUS_NO_SUCH_FILE ); +} + + +/* set mailslot information */ +DECL_HANDLER(set_mailslot_info) +{ + struct mailslot *mailslot = get_mailslot_obj( current->process, req->handle, 0 ); + + if( mailslot ) + { + int r, fd = get_unix_fd( mailslot->fd ); + + if( req->flags & MAILSLOT_SET_READ_TIMEOUT ) + mailslot->read_timeout = req->read_timeout; + reply->max_msgsize = mailslot->max_msgsize; + reply->read_timeout = mailslot->read_timeout; + reply->msg_count = mailslot_message_count(mailslot); + + /* get the size of the next message */ + r = recv( fd, NULL, 0, MSG_PEEK | MSG_TRUNC ); + if( r < 0 ) + reply->next_msgsize = MAILSLOT_NO_MESSAGE; + else + reply->next_msgsize = r; + + release_object( mailslot ); + } +} diff --git a/server/protocol.def b/server/protocol.def index da7dfe85642..d035abdf79d 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2272,3 +2272,39 @@ enum message_type @REPLY obj_handle_t new_handle; /* duplicated handle */ @END + + +/* Create a mailslot */ +@REQ(create_mailslot) + unsigned int max_msgsize; + unsigned int read_timeout; + int inherit; + VARARG(name,unicode_str); /* mailslot name */ +@REPLY + obj_handle_t handle; /* handle to the mailslot */ +@END + + +/* Open an existing mailslot */ +@REQ(open_mailslot) + unsigned int access; + int inherit; /* inherit flag */ + unsigned int sharing; /* sharing mode */ + VARARG(name,unicode_str); /* mailslot name */ +@REPLY + obj_handle_t handle; /* handle to the mailslot */ +@END + + +/* Set mailslot information */ +@REQ(set_mailslot_info) + obj_handle_t handle; /* handle to the mailslot */ + unsigned int flags; + unsigned int read_timeout; +@REPLY + unsigned int max_msgsize; + unsigned int read_timeout; + unsigned int msg_count; + unsigned int next_msgsize; +@END +#define MAILSLOT_SET_READ_TIMEOUT 1 diff --git a/server/request.h b/server/request.h index 5c8ffe2e397..5d314db61db 100644 --- a/server/request.h +++ b/server/request.h @@ -288,6 +288,9 @@ DECL_HANDLER(set_global_windows); DECL_HANDLER(adjust_token_privileges); DECL_HANDLER(get_token_privileges); DECL_HANDLER(duplicate_token); +DECL_HANDLER(create_mailslot); +DECL_HANDLER(open_mailslot); +DECL_HANDLER(set_mailslot_info); #ifdef WANT_REQUEST_HANDLERS @@ -479,6 +482,9 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_adjust_token_privileges, (req_handler)req_get_token_privileges, (req_handler)req_duplicate_token, + (req_handler)req_create_mailslot, + (req_handler)req_open_mailslot, + (req_handler)req_set_mailslot_info, }; #endif /* WANT_REQUEST_HANDLERS */ diff --git a/server/trace.c b/server/trace.c index 317d22d4520..cda0973bae6 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2696,6 +2696,49 @@ static void dump_duplicate_token_reply( const struct duplicate_token_reply *req fprintf( stderr, " new_handle=%p", req->new_handle ); } +static void dump_create_mailslot_request( const struct create_mailslot_request *req ) +{ + fprintf( stderr, " max_msgsize=%08x,", req->max_msgsize ); + fprintf( stderr, " read_timeout=%08x,", req->read_timeout ); + fprintf( stderr, " inherit=%d,", req->inherit ); + fprintf( stderr, " name=" ); + dump_varargs_unicode_str( cur_size ); +} + +static void dump_create_mailslot_reply( const struct create_mailslot_reply *req ) +{ + fprintf( stderr, " handle=%p", req->handle ); +} + +static void dump_open_mailslot_request( const struct open_mailslot_request *req ) +{ + fprintf( stderr, " access=%08x,", req->access ); + fprintf( stderr, " inherit=%d,", req->inherit ); + fprintf( stderr, " sharing=%08x,", req->sharing ); + fprintf( stderr, " name=" ); + dump_varargs_unicode_str( cur_size ); +} + +static void dump_open_mailslot_reply( const struct open_mailslot_reply *req ) +{ + fprintf( stderr, " handle=%p", req->handle ); +} + +static void dump_set_mailslot_info_request( const struct set_mailslot_info_request *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " flags=%08x,", req->flags ); + fprintf( stderr, " read_timeout=%08x", req->read_timeout ); +} + +static void dump_set_mailslot_info_reply( const struct set_mailslot_info_reply *req ) +{ + fprintf( stderr, " max_msgsize=%08x,", req->max_msgsize ); + fprintf( stderr, " read_timeout=%08x,", req->read_timeout ); + fprintf( stderr, " msg_count=%08x,", req->msg_count ); + fprintf( stderr, " next_msgsize=%08x", req->next_msgsize ); +} + static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_new_process_request, (dump_func)dump_get_new_process_info_request, @@ -2882,6 +2925,9 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_adjust_token_privileges_request, (dump_func)dump_get_token_privileges_request, (dump_func)dump_duplicate_token_request, + (dump_func)dump_create_mailslot_request, + (dump_func)dump_open_mailslot_request, + (dump_func)dump_set_mailslot_info_request, }; static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { @@ -3070,6 +3116,9 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_adjust_token_privileges_reply, (dump_func)dump_get_token_privileges_reply, (dump_func)dump_duplicate_token_reply, + (dump_func)dump_create_mailslot_reply, + (dump_func)dump_open_mailslot_reply, + (dump_func)dump_set_mailslot_info_reply, }; static const char * const req_names[REQ_NB_REQUESTS] = { @@ -3258,6 +3307,9 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "adjust_token_privileges", "get_token_privileges", "duplicate_token", + "create_mailslot", + "open_mailslot", + "set_mailslot_info", }; /* ### make_requests end ### */