kernel32: Reimplement TransactNamedPipe on top of FSCTL_PIPE_TRANSCEIVE.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2018-03-28 22:46:51 +02:00 committed by Alexandre Julliard
parent f2cc9507aa
commit 0ca7c5c4e2
2 changed files with 162 additions and 12 deletions

View File

@ -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;
}
/***********************************************************************

View File

@ -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();
}