Jacek Caban : kernel32: Reimplement TransactNamedPipe on top of FSCTL_PIPE_TRANSCEIVE.
Alexandre Julliard
julliard at winehq.org
Thu Mar 29 19:13:29 CDT 2018
Module: wine
Branch: master
Commit: 0ca7c5c4e22fe7f0ae43596fe5ab7d27af5ff65e
URL: https://source.winehq.org/git/wine.git/?a=commit;h=0ca7c5c4e22fe7f0ae43596fe5ab7d27af5ff65e
Author: Jacek Caban <jacek at codeweavers.com>
Date: Wed Mar 28 22:46:51 2018 +0200
kernel32: Reimplement TransactNamedPipe on top of FSCTL_PIPE_TRANSCEIVE.
Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/kernel32/sync.c | 36 ++++++++----
dlls/kernel32/tests/pipe.c | 138 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 162 insertions(+), 12 deletions(-)
diff --git a/dlls/kernel32/sync.c b/dlls/kernel32/sync.c
index 4e85aed..fcf1be7 100644
--- a/dlls/kernel32/sync.c
+++ b/dlls/kernel32/sync.c
@@ -1715,29 +1715,41 @@ BOOL WINAPI DisconnectNamedPipe(HANDLE hPipe)
/***********************************************************************
* TransactNamedPipe (KERNEL32.@)
- *
- * BUGS
- * should be done as a single operation in the wineserver or kernel
*/
BOOL WINAPI TransactNamedPipe(
HANDLE handle, LPVOID write_buf, DWORD write_size, LPVOID read_buf,
DWORD read_size, LPDWORD bytes_read, LPOVERLAPPED overlapped)
{
- BOOL r;
- DWORD count;
+ IO_STATUS_BLOCK default_iosb, *iosb = &default_iosb;
+ HANDLE event = NULL;
+ void *cvalue = NULL;
+ NTSTATUS status;
- TRACE("%p %p %d %p %d %p %p\n",
- handle, write_buf, write_size, read_buf,
+ TRACE("%p %p %u %p %u %p %p\n", handle, write_buf, write_size, read_buf,
read_size, bytes_read, overlapped);
if (overlapped)
- FIXME("Doesn't support overlapped operation as yet\n");
+ {
+ event = overlapped->hEvent;
+ iosb = (IO_STATUS_BLOCK *)overlapped;
+ if (((ULONG_PTR)event & 1) == 0) cvalue = overlapped;
+ }
+ else
+ {
+ iosb->Information = 0;
+ }
- r = WriteFile(handle, write_buf, write_size, &count, NULL);
- if (r)
- r = ReadFile(handle, read_buf, read_size, bytes_read, NULL);
+ status = NtFsControlFile(handle, event, NULL, cvalue, iosb, FSCTL_PIPE_TRANSCEIVE,
+ write_buf, write_size, read_buf, read_size);
- return r;
+ if (bytes_read) *bytes_read = overlapped && status ? 0 : iosb->Information;
+
+ if (status)
+ {
+ SetLastError(RtlNtStatusToDosError(status));
+ return FALSE;
+ }
+ return TRUE;
}
/***********************************************************************
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c
index 22d120f..fa677cf 100644
--- a/dlls/kernel32/tests/pipe.c
+++ b/dlls/kernel32/tests/pipe.c
@@ -3011,6 +3011,44 @@ static void test_blocking_rw(HANDLE writer, HANDLE reader, DWORD buf_size, BOOL
test_flush_done(flush_thread);
}
+#define overlapped_transact(a,b,c,d,e,f) _overlapped_transact(__LINE__,a,b,c,d,e,f)
+static void _overlapped_transact(unsigned line, HANDLE caller, void *write_buf, DWORD write_size,
+ void *read_buf, DWORD read_size, OVERLAPPED *overlapped)
+{
+ BOOL res;
+
+ memset(overlapped, 0, sizeof(*overlapped));
+ overlapped->hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
+ res = TransactNamedPipe(caller, write_buf, write_size, read_buf, read_size, NULL, overlapped);
+ ok_(__FILE__,line)(!res && GetLastError() == ERROR_IO_PENDING,
+ "TransactNamedPipe returned: %x(%u)\n", res, GetLastError());
+}
+
+#define overlapped_transact_failure(a,b,c,d,e,f) _overlapped_transact_failure(__LINE__,a,b,c,d,e,f)
+static void _overlapped_transact_failure(unsigned line, HANDLE caller, void *write_buf, DWORD write_size,
+ void *read_buf, DWORD read_size, DWORD expected_error)
+{
+ OVERLAPPED overlapped;
+ BOOL res;
+
+ memset(&overlapped, 0, sizeof(overlapped));
+ overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
+ res = TransactNamedPipe(caller, write_buf, write_size, read_buf, read_size, NULL, &overlapped);
+ ok_(__FILE__,line)(!res, "TransactNamedPipe succeeded\n");
+
+ if (GetLastError() == ERROR_IO_PENDING) /* win8+ */
+ {
+ _test_overlapped_failure(line, caller, &overlapped, expected_error);
+ }
+ else
+ {
+ ok_(__FILE__,line)(GetLastError() == expected_error,
+ "TransactNamedPipe returned error %u, expected %u\n",
+ GetLastError(), expected_error);
+ CloseHandle(overlapped.hEvent);
+ }
+}
+
static void child_process_write_pipe(HANDLE pipe)
{
OVERLAPPED overlapped;
@@ -3146,6 +3184,105 @@ static void test_overlapped_transport(BOOL msg_mode, BOOL msg_read_mode)
CloseHandle(client);
}
+static void test_transact(HANDLE caller, HANDLE callee, DWORD write_buf_size, DWORD read_buf_size)
+{
+ OVERLAPPED overlapped, overlapped2, read_overlapped, write_overlapped;
+ char buf[10000], read_buf[10000];
+
+ memset(buf, 0xaa, sizeof(buf));
+
+ /* simple transact call */
+ overlapped_transact(caller, (BYTE*)"abc", 3, read_buf, 100, &overlapped);
+ overlapped_write_sync(callee, (BYTE*)"test", 4);
+ test_overlapped_result(caller, &overlapped, 4, FALSE);
+ ok(!memcmp(read_buf, "test", 4), "unexpected read_buf\n");
+ overlapped_read_sync(callee, read_buf, 1000, 3, FALSE);
+ ok(!memcmp(read_buf, "abc", 3), "unexpected read_buf\n");
+
+ /* transact fails if there is already data in read buffer */
+ overlapped_write_sync(callee, buf, 1);
+ overlapped_transact_failure(caller, buf, 2, read_buf, 1, ERROR_PIPE_BUSY);
+ overlapped_read_sync(caller, read_buf, 1000, 1, FALSE);
+
+ /* transact doesn't block on write */
+ overlapped_write_async(caller, buf, write_buf_size+2000, &write_overlapped);
+ overlapped_transact(caller, buf, 2, read_buf, 1, &overlapped);
+ test_not_signaled(overlapped.hEvent);
+ overlapped_write_sync(callee, buf, 1);
+ test_overlapped_result(caller, &overlapped, 1, FALSE);
+ overlapped_read_sync(callee, read_buf, sizeof(read_buf), write_buf_size+2000, FALSE);
+ test_overlapped_result(caller, &write_overlapped, write_buf_size+2000, FALSE);
+ overlapped_read_sync(callee, read_buf, sizeof(read_buf), 2, FALSE);
+
+ /* transact with already pending read */
+ overlapped_read_async(callee, read_buf, 10, &read_overlapped);
+ overlapped_transact(caller, buf, 5, read_buf, 6, &overlapped);
+ test_overlapped_result(callee, &read_overlapped, 5, FALSE);
+ test_not_signaled(overlapped.hEvent);
+ overlapped_write_sync(callee, buf, 10);
+ test_overlapped_result(caller, &overlapped, 6, TRUE);
+ overlapped_read_sync(caller, read_buf, sizeof(read_buf), 4, FALSE);
+
+ /* 0-size messages */
+ overlapped_transact(caller, buf, 5, read_buf, 0, &overlapped);
+ overlapped_read_sync(callee, read_buf, sizeof(read_buf), 5, FALSE);
+ overlapped_write_sync(callee, buf, 0);
+ test_overlapped_result(caller, &overlapped, 0, FALSE);
+
+ overlapped_transact(caller, buf, 0, read_buf, 0, &overlapped);
+ overlapped_read_sync(callee, read_buf, sizeof(read_buf), 0, FALSE);
+ test_not_signaled(overlapped.hEvent);
+ overlapped_write_sync(callee, buf, 0);
+ test_overlapped_result(caller, &overlapped, 0, FALSE);
+
+ /* reply transact with another transact */
+ overlapped_transact(caller, buf, 3, read_buf, 100, &overlapped);
+ overlapped_read_sync(callee, read_buf, 1000, 3, FALSE);
+ overlapped_transact(callee, buf, 4, read_buf, 100, &overlapped2);
+ test_overlapped_result(caller, &overlapped, 4, FALSE);
+ overlapped_write_sync(caller, buf, 1);
+ test_overlapped_result(caller, &overlapped2, 1, FALSE);
+
+ if (!pCancelIoEx) return;
+
+ /* cancel keeps written data */
+ overlapped_write_async(caller, buf, write_buf_size+2000, &write_overlapped);
+ overlapped_transact(caller, buf, 2, read_buf, 1, &overlapped);
+ test_not_signaled(overlapped.hEvent);
+ cancel_overlapped(caller, &overlapped);
+ overlapped_read_sync(callee, read_buf, sizeof(read_buf), write_buf_size+2000, FALSE);
+ test_overlapped_result(caller, &write_overlapped, write_buf_size+2000, FALSE);
+ overlapped_read_sync(callee, read_buf, sizeof(read_buf), 2, FALSE);
+}
+
+static void test_TransactNamedPipe(void)
+{
+ HANDLE client, server;
+ BYTE buf[10];
+
+ create_overlapped_pipe(PIPE_TYPE_BYTE, &client, &server);
+ overlapped_transact_failure(client, buf, 2, buf, 1, ERROR_BAD_PIPE);
+ CloseHandle(client);
+ CloseHandle(server);
+
+ create_overlapped_pipe(PIPE_TYPE_MESSAGE | PIPE_READMODE_BYTE, &client, &server);
+ overlapped_transact_failure(client, buf, 2, buf, 1, ERROR_BAD_PIPE);
+ CloseHandle(client);
+ CloseHandle(server);
+
+ trace("testing server->client transaction...\n");
+ create_overlapped_pipe(PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, &client, &server);
+ test_transact(server, client, 5000, 6000);
+ CloseHandle(client);
+ CloseHandle(server);
+
+ trace("testing client->server transaction...\n");
+ create_overlapped_pipe(PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, &client, &server);
+ test_transact(client, server, 6000, 5000);
+ CloseHandle(client);
+ CloseHandle(server);
+}
+
START_TEST(pipe)
{
char **argv;
@@ -3186,4 +3323,5 @@ START_TEST(pipe)
test_overlapped_transport(TRUE, FALSE);
test_overlapped_transport(TRUE, TRUE);
test_overlapped_transport(FALSE, FALSE);
+ test_TransactNamedPipe();
}
More information about the wine-cvs
mailing list