Added patch to add support for named pipe message mode.

This commit is contained in:
Sebastian Lackner 2014-12-27 17:33:55 +01:00
parent 1f74cc531e
commit 9c6e895b0b
21 changed files with 3277 additions and 28 deletions

View File

@ -37,7 +37,7 @@ Wine. All those differences are also documented on the
Included bug fixes and improvements
===================================
**Bugfixes and features included in the next upcoming release [11]:**
**Bugfixes and features included in the next upcoming release [12]:**
* Add stub for D3DXComputeTangentFrameEx ([Wine Bug #31984](https://bugs.winehq.org/show_bug.cgi?id=31984))
* Add stub for D3DXIntersect
@ -48,6 +48,7 @@ Included bug fixes and improvements
* Implement ID3DXEffect::FindNextValidTechnique ([Wine Bug #34101](https://bugs.winehq.org/show_bug.cgi?id=34101))
* Implement IDXGIOutput::GetDesc
* Support for SLGetWindowsInformationDWORD ([Wine Bug #36709](https://bugs.winehq.org/show_bug.cgi?id=36709))
* Support for named pipe message mode ([Wine Bug #17195](https://bugs.winehq.org/show_bug.cgi?id=17195))
* Try harder to get the host name address in getaddrinfo() ([Wine Bug #29609](https://bugs.winehq.org/show_bug.cgi?id=29609))
* Use actual program name if available to describe PulseAudio streams

1
debian/changelog vendored
View File

@ -18,6 +18,7 @@ wine-staging (1.7.34) UNRELEASED; urgency=low
* Added patch to use actual program name if available to describe PulseAudio streams.
* Added patch to try harder to get the host name address in getaddrinfo().
* Added patch to fix invalid usage of RegOpenKeyExW in msdmo.
* Added patch to add support for named pipe message mode.
* Removed patch to implement combase HSTRING objects (accepted upstream).
* Removed patch to add fake ProductId to registry (accepted upstream).
* Removed patch to implement stubs for MFStartup and MFShutdown (accepted upstream).

View File

@ -761,15 +761,49 @@ kernel32-GetVolumePathName.ok:
# |
# | This patchset fixes the following Wine bugs:
# | * [#16550] Fix for ConnectNamedPort return value in overlapped mode
# | * [#17195] Support for named pipe message mode
# |
# | Modified files:
# | * dlls/kernel32/sync.c
# | * dlls/kernel32/file.c, dlls/kernel32/sync.c, dlls/kernel32/tests/pipe.c, dlls/ntdll/file.c, server/named_pipe.c,
# | server/protocol.def, server/sock.c, server/sock.h
# |
.INTERMEDIATE: kernel32-Named_Pipe.ok
kernel32-Named_Pipe.ok:
$(call APPLY_FILE,kernel32-Named_Pipe/0001-kernel32-ConnectNamedPort-should-return-FALSE-and-se.patch)
$(call APPLY_FILE,kernel32-Named_Pipe/0002-kernel32-tests-Add-tests-for-PeekNamedPipe-with-part.patch)
$(call APPLY_FILE,kernel32-Named_Pipe/0003-kernel32-tests-Add-tests-for-sending-and-receiving-l.patch)
$(call APPLY_FILE,kernel32-Named_Pipe/0004-kernel32-tests-Add-tests-for-closing-named-pipes.patch)
$(call APPLY_FILE,kernel32-Named_Pipe/0005-server-Show-warning-if-message-mode-is-not-supported.patch)
$(call APPLY_FILE,kernel32-Named_Pipe/0006-ntdll-Unify-similar-code-in-NtReadFile-and-FILE_Asyn.patch)
$(call APPLY_FILE,kernel32-Named_Pipe/0007-ntdll-Move-logic-to-check-for-broken-pipe-into-a-sep.patch)
$(call APPLY_FILE,kernel32-Named_Pipe/0008-ntdll-Unify-similar-code-in-NtWriteFile-and-FILE_Asy.patch)
$(call APPLY_FILE,kernel32-Named_Pipe/0009-server-Use-SOCK_SEQPACKET-socket-in-combination-with.patch)
$(call APPLY_FILE,kernel32-Named_Pipe/0010-ntdll-Add-handling-for-partially-received-messages-i.patch)
$(call APPLY_FILE,kernel32-Named_Pipe/0011-kernel32-tests-Add-more-tests-with-overlapped-IO-and.patch)
$(call APPLY_FILE,kernel32-Named_Pipe/0012-ntdll-Fix-some-tests-for-overlapped-partial-reads.patch)
$(call APPLY_FILE,kernel32-Named_Pipe/0013-kernel32-tests-Test-sending-peeking-and-receiving-an.patch)
$(call APPLY_FILE,kernel32-Named_Pipe/0014-ntdll-Add-support-for-nonblocking-pipes.patch)
$(call APPLY_FILE,kernel32-Named_Pipe/0015-kernel32-tests-Add-tests-for-PIPE_NOWAIT-in-message-.patch)
$(call APPLY_FILE,kernel32-Named_Pipe/0016-ntdll-Allow-to-set-PIPE_NOWAIT-on-byte-mode-pipes.patch)
$(call APPLY_FILE,kernel32-Named_Pipe/0017-kernel32-tests-Add-additional-tests-for-PIPE_NOWAIT-.patch)
@( \
echo '+ { "Dan Kegel", "kernel32: ConnectNamedPort should return FALSE and set ERROR_PIPE_CONNECTED on success in overlapped mode.", 1 },'; \
echo '+ { "Sebastian Lackner", "kernel32/tests: Add tests for PeekNamedPipe with partial received messages.", 1 },'; \
echo '+ { "Sebastian Lackner", "kernel32/tests: Add tests for sending and receiving large messages.", 1 },'; \
echo '+ { "Adam Martinson", "kernel32/tests: Add tests for closing named pipes.", 1 },'; \
echo '+ { "Sebastian Lackner", "server: Show warning if message mode is not supported.", 1 },'; \
echo '+ { "Sebastian Lackner", "ntdll: Unify similar code in NtReadFile and FILE_AsyncReadService.", 1 },'; \
echo '+ { "Sebastian Lackner", "ntdll: Move logic to check for broken pipe into a separate function.", 1 },'; \
echo '+ { "Sebastian Lackner", "ntdll: Unify similar code in NtWriteFile and FILE_AsyncWriteService.", 1 },'; \
echo '+ { "Sebastian Lackner", "server: Use SOCK_SEQPACKET socket in combination with SO_PEEK_OFF to implement message mode on Unix.", 1 },'; \
echo '+ { "Sebastian Lackner", "ntdll: Add handling for partially received messages in NtReadFile.", 1 },'; \
echo '+ { "Sebastian Lackner", "kernel32/tests: Add more tests with overlapped IO and partial reads from named pipes.", 1 },'; \
echo '+ { "Sebastian Lackner", "ntdll: Fix some tests for overlapped partial reads.", 1 },'; \
echo '+ { "Sebastian Lackner", "kernel32/tests: Test sending, peeking and receiving an empty message.", 1 },'; \
echo '+ { "Sebastian Lackner", "ntdll: Add support for nonblocking pipes.", 1 },'; \
echo '+ { "Sebastian Lackner", "kernel32/tests: Add tests for PIPE_NOWAIT in message mode.", 1 },'; \
echo '+ { "Sebastian Lackner", "ntdll: Allow to set PIPE_NOWAIT on byte-mode pipes.", 1 },'; \
echo '+ { "Sebastian Lackner", "kernel32/tests: Add additional tests for PIPE_NOWAIT in overlapped mode.", 1 },'; \
) > kernel32-Named_Pipe.ok
# Patchset kernel32-Profile

View File

@ -0,0 +1,280 @@
From a08cd0cbb65ca0c53857c35e40f6d3d910119b22 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Thu, 31 Jul 2014 00:28:59 +0200
Subject: kernel32/tests: Add tests for PeekNamedPipe with partial received
messages.
This patch adds a couple more tests to ensure that PeekNamedPipe correctly
returns the number of remaining bytes which are part of the same message.
Moreover we have to be sure, that PeekNamedPipe also returns the same
information from all threads.
Changes in v2:
* Also add tests for reverse direction.
Changes in v3:
* Fix compiler warning on x86_64.
---
dlls/kernel32/tests/pipe.c | 142 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 140 insertions(+), 2 deletions(-)
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c
index 056f95b..a252bc8 100644
--- a/dlls/kernel32/tests/pipe.c
+++ b/dlls/kernel32/tests/pipe.c
@@ -46,7 +46,8 @@ static void CALLBACK user_apc(ULONG_PTR param)
enum rpcThreadOp
{
- RPC_READFILE
+ RPC_READFILE,
+ RPC_PEEKNAMEDPIPE
};
struct rpcThreadArgs
@@ -54,7 +55,7 @@ struct rpcThreadArgs
ULONG_PTR returnValue;
DWORD lastError;
enum rpcThreadOp op;
- ULONG_PTR args[5];
+ ULONG_PTR args[6];
};
static DWORD CALLBACK rpcThreadMain(LPVOID arg)
@@ -73,6 +74,15 @@ static DWORD CALLBACK rpcThreadMain(LPVOID arg)
(LPOVERLAPPED)rpcargs->args[4] ); /* overlapped */
break;
+ case RPC_PEEKNAMEDPIPE:
+ rpcargs->returnValue = (ULONG_PTR)PeekNamedPipe( (HANDLE)rpcargs->args[0], /* hPipe */
+ (LPVOID)rpcargs->args[1], /* lpvBuffer */
+ (DWORD)rpcargs->args[2], /* cbBuffer */
+ (LPDWORD)rpcargs->args[3], /* lpcbRead */
+ (LPDWORD)rpcargs->args[4], /* lpcbAvail */
+ (LPDWORD)rpcargs->args[5] ); /* lpcbMessage */
+ break;
+
default:
SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
rpcargs->returnValue = 0;
@@ -109,6 +119,33 @@ static BOOL RpcReadFile(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD
return (BOOL)rpcargs.returnValue;
}
+/* Runs PeekNamedPipe(...) from a different thread */
+static BOOL RpcPeekNamedPipe(HANDLE hPipe, LPVOID lpvBuffer, DWORD cbBuffer,
+ LPDWORD lpcbRead, LPDWORD lpcbAvail, LPDWORD lpcbMessage)
+{
+ struct rpcThreadArgs rpcargs;
+ HANDLE thread;
+ DWORD threadId;
+
+ rpcargs.returnValue = 0;
+ rpcargs.lastError = GetLastError();
+ rpcargs.op = RPC_PEEKNAMEDPIPE;
+ rpcargs.args[0] = (ULONG_PTR)hPipe;
+ rpcargs.args[1] = (ULONG_PTR)lpvBuffer;
+ rpcargs.args[2] = (ULONG_PTR)cbBuffer;
+ rpcargs.args[3] = (ULONG_PTR)lpcbRead;
+ rpcargs.args[4] = (ULONG_PTR)lpcbAvail;
+ rpcargs.args[5] = (ULONG_PTR)lpcbMessage;
+
+ thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId);
+ ok(thread != NULL, "CreateThread failed. %d\n", GetLastError());
+ ok(WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0,"WaitForSingleObject failed with %d.\n", GetLastError());
+ CloseHandle(thread);
+
+ SetLastError(rpcargs.lastError);
+ return (BOOL)rpcargs.returnValue;
+}
+
static void test_CreateNamedPipe(int pipemode)
{
HANDLE hnp;
@@ -118,6 +155,7 @@ static void test_CreateNamedPipe(int pipemode)
char ibuf[32], *pbuf;
DWORD written;
DWORD readden;
+ DWORD leftmsg;
DWORD avail;
DWORD lpmode;
BOOL ret;
@@ -232,9 +270,21 @@ static void test_CreateNamedPipe(int pipemode)
ok(written == sizeof(obuf2), "write file len\n");
ok(ReadFile(hFile, ibuf, 4, &readden, NULL), "ReadFile\n");
ok(readden == 4, "read got %d bytes\n", readden);
+ readden = leftmsg = -1;
+ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe\n");
+ ok(readden == sizeof(obuf2) - 4, "peek got %d bytes total\n", readden);
+ if (pipemode == PIPE_TYPE_BYTE)
+ ok(leftmsg == 0, "peek got %d bytes left in message\n", leftmsg);
+ else
+ todo_wine
+ ok(leftmsg == sizeof(obuf2) - 4, "peek got %d bytes left in message\n", leftmsg);
ok(ReadFile(hFile, ibuf + 4, sizeof(ibuf) - 4, &readden, NULL), "ReadFile\n");
ok(readden == sizeof(obuf2) - 4, "read got %d bytes\n", readden);
ok(memcmp(obuf2, ibuf, written) == 0, "content check\n");
+ readden = leftmsg = -1;
+ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe\n");
+ ok(readden == 0, "peek got %d bytes total\n", readden);
+ ok(leftmsg == 0, "peek got %d bytes left in message\n", leftmsg);
memset(ibuf, 0, sizeof(ibuf));
ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
@@ -447,6 +497,16 @@ static void test_CreateNamedPipe(int pipemode)
ok(written == sizeof(obuf), "write file len 9\n");
ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), "WriteFile 9\n");
ok(written == sizeof(obuf2), "write file len 9\n");
+ readden = leftmsg = -1;
+ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 9\n");
+ ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 9\n", readden);
+ todo_wine
+ ok(leftmsg == sizeof(obuf), "peek got %d bytes left in message 9\n", leftmsg);
+ readden = leftmsg = -1;
+ ok(RpcPeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 9\n");
+ ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 9\n", readden);
+ todo_wine
+ ok(leftmsg == sizeof(obuf), "peek got %d bytes left in message 9\n", leftmsg);
SetLastError(0xdeadbeef);
todo_wine
ok(!ReadFile(hFile, ibuf, 4, &readden, NULL), "ReadFile 9\n");
@@ -460,6 +520,16 @@ static void test_CreateNamedPipe(int pipemode)
todo_wine
ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n");
ok(readden == 4, "read got %d bytes 9\n", readden);
+ readden = leftmsg = -1;
+ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 9\n");
+ ok(readden == sizeof(obuf) - 8 + sizeof(obuf2), "peek got %d bytes total 9\n", readden);
+ todo_wine
+ ok(leftmsg == sizeof(obuf) - 8, "peek got %d bytes left in message 9\n", leftmsg);
+ readden = leftmsg = -1;
+ ok(RpcPeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 9\n");
+ ok(readden == sizeof(obuf) - 8 + sizeof(obuf2), "peek got %d bytes total 9\n", readden);
+ todo_wine
+ ok(leftmsg == sizeof(obuf) - 8, "peek got %d bytes left in message 9\n", leftmsg);
ret = RpcReadFile(hFile, ibuf + 8, sizeof(ibuf), &readden, NULL);
ok(ret, "RpcReadFile 9\n");
todo_wine
@@ -468,6 +538,14 @@ static void test_CreateNamedPipe(int pipemode)
if (readden <= sizeof(obuf) - 8) /* blocks forever if second part was already received */
{
memset(ibuf, 0, sizeof(ibuf));
+ readden = leftmsg = -1;
+ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 9\n");
+ ok(readden == sizeof(obuf2), "peek got %d bytes total 9\n", readden);
+ ok(leftmsg == sizeof(obuf2), "peek got %d bytes left in message 9\n", leftmsg);
+ readden = leftmsg = -1;
+ ok(RpcPeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 9\n");
+ ok(readden == sizeof(obuf2), "peek got %d bytes total 9\n", readden);
+ ok(leftmsg == sizeof(obuf2), "peek got %d bytes left in message 9\n", leftmsg);
SetLastError(0xdeadbeef);
ret = RpcReadFile(hFile, ibuf, 4, &readden, NULL);
ok(!ret, "RpcReadFile 9\n");
@@ -480,11 +558,27 @@ static void test_CreateNamedPipe(int pipemode)
todo_wine
ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n");
ok(readden == 4, "read got %d bytes 9\n", readden);
+ readden = leftmsg = -1;
+ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 9\n");
+ ok(readden == sizeof(obuf2) - 8, "peek got %d bytes total 9\n", readden);
+ ok(leftmsg == sizeof(obuf2) - 8, "peek got %d bytes left in message 9\n", leftmsg);
+ readden = leftmsg = -1;
+ ok(RpcPeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 9\n");
+ ok(readden == sizeof(obuf2) - 8, "peek got %d bytes total 9\n", readden);
+ ok(leftmsg == sizeof(obuf2) - 8, "peek got %d bytes left in message 9\n", leftmsg);
ret = RpcReadFile(hFile, ibuf + 8, sizeof(ibuf), &readden, NULL);
ok(ret, "RpcReadFile 9\n");
ok(readden == sizeof(obuf2) - 8, "read got %d bytes 9\n", readden);
ok(memcmp(obuf2, ibuf, sizeof(obuf2)) == 0, "content check 9\n");
}
+ readden = leftmsg = -1;
+ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 9\n");
+ ok(readden == 0, "peek got %d bytes total 9\n", readden);
+ ok(leftmsg == 0, "peek got %d bytes left in message 9\n", leftmsg);
+ readden = leftmsg = -1;
+ ok(RpcPeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 9\n");
+ ok(readden == 0, "peek got %d bytes total 9\n", readden);
+ ok(leftmsg == 0, "peek got %d bytes left in message 9\n", leftmsg);
/* Now the reverse direction */
memset(ibuf, 0, sizeof(ibuf));
@@ -492,6 +586,16 @@ static void test_CreateNamedPipe(int pipemode)
ok(written == sizeof(obuf2), "write file len 10\n");
ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile 10\n");
ok(written == sizeof(obuf), "write file len 10\n");
+ readden = leftmsg = -1;
+ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 10\n");
+ ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 10\n", readden);
+ todo_wine
+ ok(leftmsg == sizeof(obuf2), "peek got %d bytes left in message 10\n", leftmsg);
+ readden = leftmsg = -1;
+ ok(RpcPeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 10\n");
+ ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 10\n", readden);
+ todo_wine
+ ok(leftmsg == sizeof(obuf2), "peek got %d bytes left in message 10\n", leftmsg);
SetLastError(0xdeadbeef);
todo_wine
ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile 10\n");
@@ -505,6 +609,16 @@ static void test_CreateNamedPipe(int pipemode)
todo_wine
ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n");
ok(readden == 4, "read got %d bytes 10\n", readden);
+ readden = leftmsg = -1;
+ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 10\n");
+ ok(readden == sizeof(obuf2) - 8 + sizeof(obuf), "peek got %d bytes total 10\n", readden);
+ todo_wine
+ ok(leftmsg == sizeof(obuf2) - 8, "peek got %d bytes left in message 10\n", leftmsg);
+ readden = leftmsg = -1;
+ ok(RpcPeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 10\n");
+ ok(readden == sizeof(obuf2) - 8 + sizeof(obuf), "peek got %d bytes total 10\n", readden);
+ todo_wine
+ ok(leftmsg == sizeof(obuf2) - 8, "peek got %d bytes left in message 10\n", leftmsg);
ret = RpcReadFile(hnp, ibuf + 8, sizeof(ibuf), &readden, NULL);
ok(ret, "RpcReadFile 10\n");
todo_wine
@@ -513,6 +627,14 @@ static void test_CreateNamedPipe(int pipemode)
if (readden <= sizeof(obuf2) - 8) /* blocks forever if second part was already received */
{
memset(ibuf, 0, sizeof(ibuf));
+ readden = leftmsg = -1;
+ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 10\n");
+ ok(readden == sizeof(obuf), "peek got %d bytes total 10\n", readden);
+ ok(leftmsg == sizeof(obuf), "peek got %d bytes left in message 10\n", leftmsg);
+ readden = leftmsg = -1;
+ ok(RpcPeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 10\n");
+ ok(readden == sizeof(obuf), "peek got %d bytes total 10\n", readden);
+ ok(leftmsg == sizeof(obuf), "peek got %d bytes left in message 10\n", leftmsg);
SetLastError(0xdeadbeef);
ret = RpcReadFile(hnp, ibuf, 4, &readden, NULL);
ok(!ret, "RpcReadFile 10\n");
@@ -525,11 +647,27 @@ static void test_CreateNamedPipe(int pipemode)
todo_wine
ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n");
ok(readden == 4, "read got %d bytes 10\n", readden);
+ readden = leftmsg = -1;
+ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 10\n");
+ ok(readden == sizeof(obuf) - 8, "peek got %d bytes total 10\n", readden);
+ ok(leftmsg == sizeof(obuf) - 8, "peek got %d bytes left in message 10\n", leftmsg);
+ readden = leftmsg = -1;
+ ok(RpcPeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 10\n");
+ ok(readden == sizeof(obuf) - 8, "peek got %d bytes total 10\n", readden);
+ ok(leftmsg == sizeof(obuf) - 8, "peek got %d bytes left in message 10\n", leftmsg);
ret = RpcReadFile(hnp, ibuf + 8, sizeof(ibuf), &readden, NULL);
ok(ret, "RpcReadFile 10\n");
ok(readden == sizeof(obuf) - 8, "read got %d bytes 10\n", readden);
ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check 10\n");
}
+ readden = leftmsg = -1;
+ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 10\n");
+ ok(readden == 0, "peek got %d bytes total 10\n", readden);
+ ok(leftmsg == 0, "peek got %d bytes left in message 10\n", leftmsg);
+ readden = leftmsg = -1;
+ ok(RpcPeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 10\n");
+ ok(readden == 0, "peek got %d bytes total 10\n", readden);
+ ok(leftmsg == 0, "peek got %d bytes left in message 10\n", leftmsg);
}
--
2.1.3

View File

@ -0,0 +1,168 @@
From 695d78fbb48472fce38f103fba76f56c36a4cb5d Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sun, 3 Aug 2014 23:14:35 +0200
Subject: kernel32/tests: Add tests for sending and receiving large messages.
This set of tests seems to confirm that on Windows, there is no upper size
limit where messages are splitted. The kernel seems to temporarily allocate
additional buffers (or use existing buffers very efficient), so WriteFile()
can never fail because of size limitations.
Changes in v2:
* Avoid compilation warning on x86_64.
---
dlls/kernel32/tests/pipe.c | 124 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 124 insertions(+)
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c
index a252bc8..246ee30 100644
--- a/dlls/kernel32/tests/pipe.c
+++ b/dlls/kernel32/tests/pipe.c
@@ -47,6 +47,7 @@ static void CALLBACK user_apc(ULONG_PTR param)
enum rpcThreadOp
{
RPC_READFILE,
+ RPC_WRITEFILE,
RPC_PEEKNAMEDPIPE
};
@@ -74,6 +75,14 @@ static DWORD CALLBACK rpcThreadMain(LPVOID arg)
(LPOVERLAPPED)rpcargs->args[4] ); /* overlapped */
break;
+ case RPC_WRITEFILE:
+ rpcargs->returnValue = (ULONG_PTR)WriteFile( (HANDLE)rpcargs->args[0], /* hFile */
+ (LPCVOID)rpcargs->args[1], /* buffer */
+ (DWORD)rpcargs->args[2], /* bytesToWrite */
+ (LPDWORD)rpcargs->args[3], /* bytesWritten */
+ (LPOVERLAPPED)rpcargs->args[4] ); /* overlapped */
+ break;
+
case RPC_PEEKNAMEDPIPE:
rpcargs->returnValue = (ULONG_PTR)PeekNamedPipe( (HANDLE)rpcargs->args[0], /* hPipe */
(LPVOID)rpcargs->args[1], /* lpvBuffer */
@@ -671,6 +680,121 @@ static void test_CreateNamedPipe(int pipemode)
}
+ /* Test behaviour for very huge messages (which don't fit completely in the buffer) */
+ {
+ static char big_obuf[512 * 1024];
+ static char big_ibuf[512 * 1024];
+ struct rpcThreadArgs rpcargs;
+ HANDLE thread;
+ DWORD threadId;
+ memset(big_obuf, 0xAA, sizeof(big_obuf));
+
+ /* Ensure that both pipes are empty before we continue with the next test */
+ while (PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL) && readden > 0)
+ ok(ReadFile(hFile, big_ibuf, sizeof(big_ibuf), &readden, NULL) ||
+ GetLastError() == ERROR_MORE_DATA, "ReadFile\n");
+
+ while (PeekNamedPipe(hnp, NULL, 0, NULL, &readden, NULL) && readden > 0)
+ ok(ReadFile(hnp, big_ibuf, sizeof(big_ibuf), &readden, NULL) ||
+ GetLastError() == ERROR_MORE_DATA, "ReadFile\n");
+
+ readden = leftmsg = -1;
+ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe\n");
+ ok(readden == 0, "peek got %d bytes total\n", readden);
+ ok(leftmsg == 0, "peek got %d bytes left in message\n", leftmsg);
+
+ /* transmit big message, receive with buffer of equal size */
+ memset(big_ibuf, 0, sizeof(big_ibuf));
+ rpcargs.returnValue = 0;
+ rpcargs.lastError = GetLastError();
+ rpcargs.op = RPC_WRITEFILE;
+ rpcargs.args[0] = (ULONG_PTR)hnp;
+ rpcargs.args[1] = (ULONG_PTR)big_obuf;
+ rpcargs.args[2] = (ULONG_PTR)sizeof(big_obuf);
+ rpcargs.args[3] = (ULONG_PTR)&written;
+ rpcargs.args[4] = (ULONG_PTR)NULL;
+
+ thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId);
+ ok(thread != NULL, "CreateThread failed. %d\n", GetLastError());
+ ret = WaitForSingleObject(thread, 200);
+ ok(ret == WAIT_TIMEOUT, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_TIMEOUT);
+ ok(ReadFile(hFile, big_ibuf, sizeof(big_ibuf), &readden, NULL), "ReadFile\n");
+ todo_wine
+ ok(readden == sizeof(big_obuf), "read got %d bytes\n", readden);
+ todo_wine
+ ok(memcmp(big_ibuf, big_obuf, sizeof(big_obuf)) == 0, "content check\n");
+ do
+ {
+ ret = WaitForSingleObject(thread, 1);
+ while (PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL) && readden > 0)
+ ok(ReadFile(hFile, big_ibuf, sizeof(big_ibuf), &readden, NULL) ||
+ GetLastError() == ERROR_MORE_DATA, "ReadFile\n");
+ }
+ while (ret == WAIT_TIMEOUT);
+ ok(WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed with %d.\n", GetLastError());
+ ok((BOOL)rpcargs.returnValue, "WriteFile\n");
+ ok(written == sizeof(big_obuf), "write file len\n");
+ CloseHandle(thread);
+
+ readden = leftmsg = -1;
+ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe\n");
+ ok(readden == 0, "peek got %d bytes total\n", readden);
+ ok(leftmsg == 0, "peek got %d bytes left in message\n", leftmsg);
+
+ /* same as above, but receive as multiple parts */
+ memset(big_ibuf, 0, sizeof(big_ibuf));
+ rpcargs.returnValue = 0;
+ rpcargs.lastError = GetLastError();
+
+ thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId);
+ ok(thread != NULL, "CreateThread failed. %d\n", GetLastError());
+ ret = WaitForSingleObject(thread, 200);
+ ok(ret == WAIT_TIMEOUT, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_TIMEOUT);
+ if (pipemode == PIPE_TYPE_BYTE)
+ {
+ ok(ReadFile(hFile, big_ibuf, 32, &readden, NULL), "ReadFile\n");
+ ok(readden == 32, "read got %d bytes\n", readden);
+ ok(ReadFile(hFile, big_ibuf + 32, 32, &readden, NULL), "ReadFile\n");
+ }
+ else
+ {
+ SetLastError(0xdeadbeef);
+ todo_wine
+ ok(!ReadFile(hFile, big_ibuf, 32, &readden, NULL), "ReadFile\n");
+ todo_wine
+ ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n");
+ ok(readden == 32, "read got %d bytes\n", readden);
+ SetLastError(0xdeadbeef);
+ todo_wine
+ ok(!ReadFile(hFile, big_ibuf + 32, 32, &readden, NULL), "ReadFile\n");
+ todo_wine
+ ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n");
+ }
+ ok(readden == 32, "read got %d bytes\n", readden);
+ ok(ReadFile(hFile, big_ibuf + 64, sizeof(big_ibuf) - 64, &readden, NULL), "ReadFile\n");
+ todo_wine
+ ok(readden == sizeof(big_obuf) - 64, "read got %d bytes\n", readden);
+ todo_wine
+ ok(memcmp(big_ibuf, big_obuf, sizeof(big_obuf)) == 0, "content check\n");
+ do
+ {
+ ret = WaitForSingleObject(thread, 1);
+ while (PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL) && readden > 0)
+ ok(ReadFile(hFile, big_ibuf, sizeof(big_ibuf), &readden, NULL) ||
+ GetLastError() == ERROR_MORE_DATA, "ReadFile\n");
+ }
+ while (ret == WAIT_TIMEOUT);
+ ok(WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed with %d.\n", GetLastError());
+ ok((BOOL)rpcargs.returnValue, "WriteFile\n");
+ ok(written == sizeof(big_obuf), "write file len\n");
+ CloseHandle(thread);
+
+ readden = leftmsg = -1;
+ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe\n");
+ ok(readden == 0, "peek got %d bytes total\n", readden);
+ ok(leftmsg == 0, "peek got %d bytes left in message\n", leftmsg);
+ }
+
/* Picky conformance tests */
/* Verify that you can't connect to pipe again
--
2.1.3

View File

@ -0,0 +1,127 @@
From ce6c2fe58743667cec2ce798bbcd938f44d71b80 Mon Sep 17 00:00:00 2001
From: Adam Martinson <adam.r.martinson@gmail.com>
Date: Tue, 18 Dec 2012 15:52:57 -0600
Subject: kernel32/tests: Add tests for closing named pipes.
Changes in v2:
* Add SetLastError().
---
dlls/kernel32/tests/pipe.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 95 insertions(+)
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c
index 246ee30..f42fe5c 100644
--- a/dlls/kernel32/tests/pipe.c
+++ b/dlls/kernel32/tests/pipe.c
@@ -923,6 +923,100 @@ static void test_CreateNamedPipe_instances_must_match(void)
ok(CloseHandle(hnp2), "CloseHandle\n");
}
+static void test_CloseNamedPipe(void)
+{
+ HANDLE hnp;
+ HANDLE hFile;
+ static const char obuf[] = "Bit Bucket";
+ char ibuf[32];
+ DWORD written;
+ DWORD readden;
+
+ hnp = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX,
+ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+ /* nMaxInstances */ 1,
+ /* nOutBufSize */ 1024,
+ /* nInBufSize */ 1024,
+ /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+ /* lpSecurityAttrib */ NULL);
+ ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
+
+ hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
+ ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError());
+
+ /* don't try to do i/o if one side couldn't be opened, as it hangs */
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ /* Make sure we can read and write a few bytes in both directions */
+ memset(ibuf, 0, sizeof(ibuf));
+ ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
+ ok(written == sizeof(obuf), "write file len 1\n");
+ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL), "Peek\n");
+ ok(readden == sizeof(obuf), "got %d bytes\n", readden);
+
+ /* close server end without disconnecting */
+ ok(CloseHandle(hnp), "CloseHandle() failed: %08x\n", GetLastError());
+
+ todo_wine
+ ok(ReadFile(hFile, ibuf, 0, &readden, NULL), "ReadFile() failed: %08x\n", GetLastError());
+ ok(readden == 0, "got %d bytes\n", readden);
+
+ memset(ibuf, 0, sizeof(ibuf));
+ ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError());
+ ok(readden == sizeof(obuf), "got %d bytes\n", readden);
+ /* pipe is empty now */
+
+ SetLastError(0xdeadbeef);
+ ok(!ReadFile(hFile, ibuf, 0, &readden, NULL), "ReadFile() succeeded\n");
+ ok(GetLastError() == ERROR_BROKEN_PIPE, "GetLastError() returned %08x, expected ERROR_BROKEN_PIPE\n", GetLastError());
+ SetLastError(0);
+
+ CloseHandle(hFile);
+ }
+
+ hnp = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX,
+ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+ /* nMaxInstances */ 1,
+ /* nOutBufSize */ 1024,
+ /* nInBufSize */ 1024,
+ /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+ /* lpSecurityAttrib */ NULL);
+ ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
+
+ hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
+ ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError());
+
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ /* Make sure we can read and write a few bytes in both directions */
+ memset(ibuf, 0, sizeof(ibuf));
+ ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
+ ok(written == sizeof(obuf), "write file len 1\n");
+ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, NULL), "Peek\n");
+ ok(readden == sizeof(obuf), "got %d bytes\n", readden);
+
+ /* close client end without disconnecting */
+ ok(CloseHandle(hFile), "CloseHandle() failed: %08x\n", GetLastError());
+
+ /* you'd think ERROR_MORE_DATA, but no */
+ todo_wine
+ ok(ReadFile(hnp, ibuf, 0, &readden, NULL), "ReadFile() failed: %08x\n", GetLastError());
+ ok(readden == 0, "got %d bytes\n", readden);
+
+ memset(ibuf, 0, sizeof(ibuf));
+ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError());
+ ok(readden == sizeof(obuf), "got %d bytes\n", readden);
+ /* pipe is empty now */
+
+ SetLastError(0xdeadbeef);
+ ok(!ReadFile(hnp, ibuf, 0, &readden, NULL), "ReadFile() succeeded\n");
+ ok(GetLastError() == ERROR_BROKEN_PIPE, "GetLastError() returned %08x, expected ERROR_BROKEN_PIPE\n", GetLastError());
+ SetLastError(0);
+
+ CloseHandle(hnp);
+ }
+}
+
/** implementation of alarm() */
static DWORD CALLBACK alarmThreadMain(LPVOID arg)
{
@@ -2425,6 +2519,7 @@ START_TEST(pipe)
test_NamedPipe_2();
test_CreateNamedPipe(PIPE_TYPE_BYTE);
test_CreateNamedPipe(PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE);
+ test_CloseNamedPipe();
test_CreatePipe();
test_impersonation();
test_overlapped();
--
2.1.3

View File

@ -0,0 +1,89 @@
From db0a81d0a3513d169335286471969b1fb9c38be1 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Mon, 4 Aug 2014 00:29:26 +0200
Subject: server: Show warning if message mode is not supported.
This patch changes the create_named_pipe wineserver call to return
which flags were supported. This allows to show a FIXME in ntdll for
missing message mode support.
---
dlls/ntdll/file.c | 14 ++++++++++----
server/named_pipe.c | 1 +
server/protocol.def | 1 +
3 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 5232027..01cef2c 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -3091,6 +3091,7 @@ NTSTATUS WINAPI NtCreateNamedPipeFile( PHANDLE handle, ULONG access,
{
struct security_descriptor *sd = NULL;
struct object_attributes objattr;
+ unsigned int flags;
NTSTATUS status;
TRACE("(%p %x %s %p %x %d %x %d %d %d %d %d %d %p)\n",
@@ -3109,16 +3110,17 @@ NTSTATUS WINAPI NtCreateNamedPipeFile( PHANDLE handle, ULONG access,
status = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
if (status != STATUS_SUCCESS) return status;
+ flags = (pipe_type ? NAMED_PIPE_MESSAGE_STREAM_WRITE : 0) |
+ (read_mode ? NAMED_PIPE_MESSAGE_STREAM_READ : 0) |
+ (completion_mode ? NAMED_PIPE_NONBLOCKING_MODE : 0);
+
SERVER_START_REQ( create_named_pipe )
{
req->access = access;
req->attributes = attr->Attributes;
req->options = options;
req->sharing = sharing;
- req->flags =
- (pipe_type ? NAMED_PIPE_MESSAGE_STREAM_WRITE : 0) |
- (read_mode ? NAMED_PIPE_MESSAGE_STREAM_READ : 0) |
- (completion_mode ? NAMED_PIPE_NONBLOCKING_MODE : 0);
+ req->flags = flags;
req->maxinstances = max_inst;
req->outsize = outbound_quota;
req->insize = inbound_quota;
@@ -3128,9 +3130,13 @@ NTSTATUS WINAPI NtCreateNamedPipeFile( PHANDLE handle, ULONG access,
wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
status = wine_server_call( req );
if (!status) *handle = wine_server_ptr_handle( reply->handle );
+ flags &= ~reply->flags; /* contains now all unsupported flags */
}
SERVER_END_REQ;
+ if (!status && (flags & (NAMED_PIPE_MESSAGE_STREAM_WRITE | NAMED_PIPE_MESSAGE_STREAM_READ)))
+ FIXME("Message mode not supported, falling back to byte mode.\n");
+
NTDLL_free_struct_sd( sd );
return status;
}
diff --git a/server/named_pipe.c b/server/named_pipe.c
index 047b62c..81741de 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -965,6 +965,7 @@ DECL_HANDLER(create_named_pipe)
return;
}
+ reply->flags = req->flags & ~(NAMED_PIPE_MESSAGE_STREAM_WRITE | NAMED_PIPE_MESSAGE_STREAM_READ);
reply->handle = 0;
if (!objattr_is_valid( objattr, get_req_data_size() ))
diff --git a/server/protocol.def b/server/protocol.def
index fc6bec5..503b02f 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2283,6 +2283,7 @@ enum message_type
unsigned int flags;
VARARG(objattr,object_attributes); /* object attributes */
@REPLY
+ unsigned int flags;
obj_handle_t handle; /* handle to the pipe */
@END
--
2.1.3

View File

@ -0,0 +1,169 @@
From a1d2578281a218b32b84d4be18c75680439f60c9 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Fri, 15 Aug 2014 22:23:08 +0200
Subject: ntdll: Unify similar code in NtReadFile and FILE_AsyncReadService.
Please note that besides merging the functions (which makes the code much
more readable) this also fixes some inconsistencies. Basically the code
from a unix fd should do the same in both cases, but it didn't...
Changes in FILE_AsyncReadService:
* Immediately retry on EINTR, chances are very good that it will
succeed in a second attempt, and its not worth to use different code
because of this small difference.
* When read(...) == 0 the result code was always STATUS_PIPE_BROKEN,
whereas NtReadFile uses different behaviour based on the fd type.
Now both implementations match, and behave the same way.
---
dlls/ntdll/file.c | 106 +++++++++++++++++++++++-------------------------------
1 file changed, 45 insertions(+), 61 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 01cef2c..a20c3e8 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -411,50 +411,63 @@ NTSTATUS FILE_GetNtStatus(void)
}
}
+/* helper function for NtReadFile and FILE_AsyncReadService */
+static NTSTATUS read_unix_fd(int fd, char *buf, ULONG *total, ULONG length,
+ enum server_fd_type type, BOOL avail_mode)
+{
+ int result;
+ for(;;)
+ {
+ result = read( fd, buf + *total, length - *total );
+ if (result >= 0)
+ {
+ *total += result;
+ if (!result || *total >= length || avail_mode)
+ {
+ if (*total)
+ return STATUS_SUCCESS;
+ switch (type)
+ {
+ case FD_TYPE_FILE:
+ case FD_TYPE_CHAR:
+ return length ? STATUS_END_OF_FILE : STATUS_SUCCESS;
+ case FD_TYPE_SERIAL:
+ return STATUS_PENDING;
+ default:
+ return STATUS_PIPE_BROKEN;
+ }
+ }
+ else if (type != FD_TYPE_FILE) /* no async I/O on regular files */
+ return STATUS_PENDING;
+ }
+ else if (errno != EINTR)
+ {
+ if (errno == EAGAIN) break;
+ return FILE_GetNtStatus();
+ }
+ }
+ return STATUS_PENDING;
+}
+
/***********************************************************************
* FILE_AsyncReadService (INTERNAL)
*/
static NTSTATUS FILE_AsyncReadService(void *user, PIO_STATUS_BLOCK iosb, NTSTATUS status, void **apc)
{
async_fileio_read *fileio = user;
- int fd, needs_close, result;
+ int fd, needs_close;
+ enum server_fd_type type;
switch (status)
{
case STATUS_ALERTED: /* got some new data */
/* check to see if the data is ready (non-blocking) */
if ((status = server_get_unix_fd( fileio->io.handle, FILE_READ_DATA, &fd,
- &needs_close, NULL, NULL )))
+ &needs_close, &type, NULL )))
break;
-
- result = read(fd, &fileio->buffer[fileio->already], fileio->count - fileio->already);
+ status = read_unix_fd( fd, fileio->buffer, &fileio->already, fileio->count,
+ type, fileio->avail_mode );
if (needs_close) close( fd );
-
- if (result < 0)
- {
- if (errno == EAGAIN || errno == EINTR)
- status = STATUS_PENDING;
- else /* check to see if the transfer is complete */
- status = FILE_GetNtStatus();
- }
- else if (result == 0)
- {
- status = fileio->already ? STATUS_SUCCESS : STATUS_PIPE_BROKEN;
- }
- else
- {
- fileio->already += result;
- if (fileio->already >= fileio->count || fileio->avail_mode)
- status = STATUS_SUCCESS;
- else
- {
- /* if we only have to read the available data, and none is available,
- * simply cancel the request. If data was available, it has been read
- * while in by previous call (NtDelayExecution)
- */
- status = (fileio->avail_mode) ? STATUS_SUCCESS : STATUS_PENDING;
- }
- }
break;
case STATUS_TIMEOUT:
@@ -603,7 +616,6 @@ static NTSTATUS get_io_avail_mode( HANDLE handle, enum server_fd_type type, BOOL
return status;
}
-
/******************************************************************************
* NtReadFile [NTDLL.@]
* ZwReadFile [NTDLL.@]
@@ -696,37 +708,9 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
for (;;)
{
- if ((result = read( unix_handle, (char *)buffer + total, length - total )) >= 0)
- {
- total += result;
- if (!result || total == length)
- {
- if (total)
- {
- status = STATUS_SUCCESS;
- goto done;
- }
- switch (type)
- {
- case FD_TYPE_FILE:
- case FD_TYPE_CHAR:
- status = length ? STATUS_END_OF_FILE : STATUS_SUCCESS;
- goto done;
- case FD_TYPE_SERIAL:
- break;
- default:
- status = STATUS_PIPE_BROKEN;
- goto done;
- }
- }
- else if (type == FD_TYPE_FILE) continue; /* no async I/O on regular files */
- }
- else if (errno != EAGAIN)
- {
- if (errno == EINTR) continue;
- if (!total) status = FILE_GetNtStatus();
+ status = read_unix_fd( unix_handle, buffer, &total, length, type, FALSE );
+ if (status != STATUS_PENDING)
goto done;
- }
if (async_read)
{
--
2.1.3

View File

@ -0,0 +1,107 @@
From 32d3c69ae680a7b6f71e203ca33f882eb0b69c47 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Fri, 15 Aug 2014 23:06:06 +0200
Subject: ntdll: Move logic to check for broken pipe into a separate function.
---
dlls/ntdll/file.c | 75 +++++++++++++++++++++++++++++--------------------------
1 file changed, 39 insertions(+), 36 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index a20c3e8..8de4b98 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -411,6 +411,31 @@ NTSTATUS FILE_GetNtStatus(void)
}
}
+/* helper function for FSCTL_PIPE_PEEK */
+static NTSTATUS unix_fd_avail(int fd, int *avail)
+{
+ struct pollfd pollfd;
+ int ret;
+ *avail = 0;
+
+#ifdef FIONREAD
+ if (ioctl( fd, FIONREAD, avail ) != 0)
+ {
+ TRACE("FIONREAD failed reason: %s\n", strerror(errno));
+ return FILE_GetNtStatus();
+ }
+ if (*avail)
+ return STATUS_SUCCESS;
+#endif
+
+ pollfd.fd = fd;
+ pollfd.events = POLLIN;
+ pollfd.revents = 0;
+ ret = poll( &pollfd, 1, 0 );
+ return (ret == -1 || (ret == 1 && (pollfd.revents & (POLLHUP|POLLERR)))) ?
+ STATUS_PIPE_BROKEN : STATUS_SUCCESS;
+}
+
/* helper function for NtReadFile and FILE_AsyncReadService */
static NTSTATUS read_unix_fd(int fd, char *buf, ULONG *total, ULONG length,
enum server_fd_type type, BOOL avail_mode)
@@ -1557,44 +1582,22 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc
if ((status = server_get_unix_fd( handle, FILE_READ_DATA, &fd, &needs_close, NULL, NULL )))
break;
-#ifdef FIONREAD
- if (ioctl( fd, FIONREAD, &avail ) != 0)
- {
- TRACE("FIONREAD failed reason: %s\n",strerror(errno));
- if (needs_close) close( fd );
- status = FILE_GetNtStatus();
- break;
- }
-#endif
- if (!avail) /* check for closed pipe */
- {
- struct pollfd pollfd;
- int ret;
-
- pollfd.fd = fd;
- pollfd.events = POLLIN;
- pollfd.revents = 0;
- ret = poll( &pollfd, 1, 0 );
- if (ret == -1 || (ret == 1 && (pollfd.revents & (POLLHUP|POLLERR))))
- {
- if (needs_close) close( fd );
- status = STATUS_PIPE_BROKEN;
- break;
- }
- }
- buffer->NamedPipeState = 0; /* FIXME */
- buffer->ReadDataAvailable = avail;
- buffer->NumberOfMessages = 0; /* FIXME */
- buffer->MessageLength = 0; /* FIXME */
- io->Information = FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
- status = STATUS_SUCCESS;
- if (avail)
+ status = unix_fd_avail( fd, &avail );
+ if (!status)
{
- ULONG data_size = out_size - FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
- if (data_size)
+ buffer->NamedPipeState = 0; /* FIXME */
+ buffer->ReadDataAvailable = avail;
+ buffer->NumberOfMessages = 0; /* FIXME */
+ buffer->MessageLength = 0; /* FIXME */
+ io->Information = FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
+ if (avail)
{
- int res = recv( fd, buffer->Data, data_size, MSG_PEEK );
- if (res >= 0) io->Information += res;
+ ULONG data_size = out_size - FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
+ if (data_size)
+ {
+ int res = recv( fd, buffer->Data, data_size, MSG_PEEK );
+ if (res >= 0) io->Information += res;
+ }
}
}
if (needs_close) close( fd );
--
2.1.3

View File

@ -0,0 +1,130 @@
From cbfe442e44c7297e524c1e3b6ae077b2c84d4ab5 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Mon, 18 Aug 2014 01:48:17 +0200
Subject: ntdll: Unify similar code in NtWriteFile and FILE_AsyncWriteService.
Changes in FILE_AsyncWriteService:
* Immediately retry on EINTR, chances are very good that it will
succeed in a second attempt, and its not worth to use different code
because of this small difference.
* Why is it STATUS_SUCCESS when we have a partial sync write, but
an error for async? Lets assume its always success...
---
dlls/ntdll/file.c | 78 +++++++++++++++++++++++++------------------------------
1 file changed, 35 insertions(+), 43 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 8de4b98..e8a1066 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -926,6 +926,37 @@ NTSTATUS WINAPI NtReadFileScatter( HANDLE file, HANDLE event, PIO_APC_ROUTINE ap
return status;
}
+/* helper function for NtWriteFile and FILE_AsyncWriteService */
+static NTSTATUS write_unix_fd(int fd, const char *buf, ULONG *total, ULONG length, enum server_fd_type type)
+{
+ int result;
+ for(;;)
+ {
+ if (!length && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET))
+ result = send( fd, buf, 0, 0 );
+ else
+ result = write( fd, buf + *total, length - *total );
+ if (result >= 0)
+ {
+ *total += result;
+ if (*total >= length)
+ return STATUS_SUCCESS;
+ else if (type != FD_TYPE_FILE) /* no async I/O on regular files */
+ return STATUS_PENDING;
+ }
+ else if (errno != EINTR)
+ {
+ if (errno == EAGAIN)
+ break;
+ else if (*total)
+ return STATUS_SUCCESS;
+ else if (errno == EFAULT)
+ return STATUS_INVALID_USER_BUFFER;
+ return FILE_GetNtStatus();
+ }
+ }
+ return STATUS_PENDING;
+}
/***********************************************************************
* FILE_AsyncWriteService (INTERNAL)
@@ -933,7 +964,7 @@ NTSTATUS WINAPI NtReadFileScatter( HANDLE file, HANDLE event, PIO_APC_ROUTINE ap
static NTSTATUS FILE_AsyncWriteService(void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status, void **apc)
{
async_fileio_write *fileio = user;
- int result, fd, needs_close;
+ int fd, needs_close;
enum server_fd_type type;
switch (status)
@@ -943,24 +974,8 @@ static NTSTATUS FILE_AsyncWriteService(void *user, IO_STATUS_BLOCK *iosb, NTSTAT
if ((status = server_get_unix_fd( fileio->io.handle, FILE_WRITE_DATA, &fd,
&needs_close, &type, NULL )))
break;
-
- if (!fileio->count && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET))
- result = send( fd, fileio->buffer, 0, 0 );
- else
- result = write( fd, &fileio->buffer[fileio->already], fileio->count - fileio->already );
-
+ status = write_unix_fd( fd, fileio->buffer, &fileio->already, fileio->count, type );
if (needs_close) close( fd );
-
- if (result < 0)
- {
- if (errno == EAGAIN || errno == EINTR) status = STATUS_PENDING;
- else status = FILE_GetNtStatus();
- }
- else
- {
- fileio->already += result;
- status = (fileio->already < fileio->count) ? STATUS_PENDING : STATUS_SUCCESS;
- }
break;
case STATUS_TIMEOUT:
@@ -1120,32 +1135,9 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
for (;;)
{
- /* zero-length writes on sockets may not work with plain write(2) */
- if (!length && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET))
- result = send( unix_handle, buffer, 0, 0 );
- else
- result = write( unix_handle, (const char *)buffer + total, length - total );
-
- if (result >= 0)
- {
- total += result;
- if (total == length)
- {
- status = STATUS_SUCCESS;
- goto done;
- }
- if (type == FD_TYPE_FILE) continue; /* no async I/O on regular files */
- }
- else if (errno != EAGAIN)
- {
- if (errno == EINTR) continue;
- if (!total)
- {
- if (errno == EFAULT) status = STATUS_INVALID_USER_BUFFER;
- else status = FILE_GetNtStatus();
- }
+ status = write_unix_fd( unix_handle, buffer, &total, length, type );
+ if (status != STATUS_PENDING)
goto done;
- }
if (async_write)
{
--
2.1.3

View File

@ -0,0 +1,542 @@
From b52ac9f6c1d7391d350e9b7cefbcbb0ac2b62516 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Mon, 4 Aug 2014 05:01:11 +0200
Subject: server: Use SOCK_SEQPACKET socket in combination with SO_PEEK_OFF to
implement message mode on Unix.
Based on ideas by Erich E. Hoover.
Similar to Windows, when a pipe has been created with message mode flags, then all
sending operations always behave in "message mode". Currently the read mode isn't
handled yet, and the default is byte mode, to stay backwards compatible.
Changes in v2:
* Show FIXME when message is too big and was splitted
* Simplify logic for FSCTL_PIPE_PEEK
Changes in v3:
* Avoid changes in later patches, directly store pipe mode in signal attributes.
Changes in v4:
* Moved changes into read_unix_fd function to make them available for async reads.
Changes in v5:
* Rebased, merged with following patch.
---
dlls/kernel32/sync.c | 2 +-
dlls/kernel32/tests/pipe.c | 9 ----
dlls/ntdll/file.c | 106 ++++++++++++++++++++++++++++++++++++-------
server/named_pipe.c | 109 ++++++++++++++++++++++++++++++++++++---------
server/sock.c | 4 +-
server/sock.h | 26 +++++++++++
6 files changed, 207 insertions(+), 49 deletions(-)
create mode 100644 server/sock.h
diff --git a/dlls/kernel32/sync.c b/dlls/kernel32/sync.c
index 12887ff..5be278e 100644
--- a/dlls/kernel32/sync.c
+++ b/dlls/kernel32/sync.c
@@ -1472,7 +1472,7 @@ BOOL WINAPI PeekNamedPipe( HANDLE hPipe, LPVOID lpvBuffer, DWORD cbBuffer,
ULONG read_size = io.Information - FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
if (lpcbAvail) *lpcbAvail = buffer->ReadDataAvailable;
if (lpcbRead) *lpcbRead = read_size;
- if (lpcbMessage) *lpcbMessage = 0; /* FIXME */
+ if (lpcbMessage) *lpcbMessage = buffer->MessageLength;
if (lpvBuffer) memcpy( lpvBuffer, buffer->Data, read_size );
}
else SetLastError( RtlNtStatusToDosError(status) );
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c
index f42fe5c..743144e 100644
--- a/dlls/kernel32/tests/pipe.c
+++ b/dlls/kernel32/tests/pipe.c
@@ -285,7 +285,6 @@ static void test_CreateNamedPipe(int pipemode)
if (pipemode == PIPE_TYPE_BYTE)
ok(leftmsg == 0, "peek got %d bytes left in message\n", leftmsg);
else
- todo_wine
ok(leftmsg == sizeof(obuf2) - 4, "peek got %d bytes left in message\n", leftmsg);
ok(ReadFile(hFile, ibuf + 4, sizeof(ibuf) - 4, &readden, NULL), "ReadFile\n");
ok(readden == sizeof(obuf2) - 4, "read got %d bytes\n", readden);
@@ -509,12 +508,10 @@ static void test_CreateNamedPipe(int pipemode)
readden = leftmsg = -1;
ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 9\n");
ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 9\n", readden);
- todo_wine
ok(leftmsg == sizeof(obuf), "peek got %d bytes left in message 9\n", leftmsg);
readden = leftmsg = -1;
ok(RpcPeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 9\n");
ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 9\n", readden);
- todo_wine
ok(leftmsg == sizeof(obuf), "peek got %d bytes left in message 9\n", leftmsg);
SetLastError(0xdeadbeef);
todo_wine
@@ -532,12 +529,10 @@ static void test_CreateNamedPipe(int pipemode)
readden = leftmsg = -1;
ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 9\n");
ok(readden == sizeof(obuf) - 8 + sizeof(obuf2), "peek got %d bytes total 9\n", readden);
- todo_wine
ok(leftmsg == sizeof(obuf) - 8, "peek got %d bytes left in message 9\n", leftmsg);
readden = leftmsg = -1;
ok(RpcPeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 9\n");
ok(readden == sizeof(obuf) - 8 + sizeof(obuf2), "peek got %d bytes total 9\n", readden);
- todo_wine
ok(leftmsg == sizeof(obuf) - 8, "peek got %d bytes left in message 9\n", leftmsg);
ret = RpcReadFile(hFile, ibuf + 8, sizeof(ibuf), &readden, NULL);
ok(ret, "RpcReadFile 9\n");
@@ -598,12 +593,10 @@ static void test_CreateNamedPipe(int pipemode)
readden = leftmsg = -1;
ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 10\n");
ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 10\n", readden);
- todo_wine
ok(leftmsg == sizeof(obuf2), "peek got %d bytes left in message 10\n", leftmsg);
readden = leftmsg = -1;
ok(RpcPeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 10\n");
ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 10\n", readden);
- todo_wine
ok(leftmsg == sizeof(obuf2), "peek got %d bytes left in message 10\n", leftmsg);
SetLastError(0xdeadbeef);
todo_wine
@@ -621,12 +614,10 @@ static void test_CreateNamedPipe(int pipemode)
readden = leftmsg = -1;
ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 10\n");
ok(readden == sizeof(obuf2) - 8 + sizeof(obuf), "peek got %d bytes total 10\n", readden);
- todo_wine
ok(leftmsg == sizeof(obuf2) - 8, "peek got %d bytes left in message 10\n", leftmsg);
readden = leftmsg = -1;
ok(RpcPeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 10\n");
ok(readden == sizeof(obuf2) - 8 + sizeof(obuf), "peek got %d bytes total 10\n", readden);
- todo_wine
ok(leftmsg == sizeof(obuf2) - 8, "peek got %d bytes left in message 10\n", leftmsg);
ret = RpcReadFile(hnp, ibuf + 8, sizeof(ibuf), &readden, NULL);
ok(ret, "RpcReadFile 10\n");
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index e8a1066..5cbfa40 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -76,6 +76,10 @@
# include <valgrind/memcheck.h>
#endif
+#ifndef SO_PEEK_OFF
+#define SO_PEEK_OFF 42
+#endif
+
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "ntstatus.h"
@@ -436,18 +440,57 @@ static NTSTATUS unix_fd_avail(int fd, int *avail)
STATUS_PIPE_BROKEN : STATUS_SUCCESS;
}
+/* returns the pipe flags for a file descriptor */
+static inline int get_pipe_flags(int fd)
+{
+#ifdef __linux__
+ return fcntl( fd, F_GETSIG );
+#else
+ return 0;
+#endif
+}
+
/* helper function for NtReadFile and FILE_AsyncReadService */
static NTSTATUS read_unix_fd(int fd, char *buf, ULONG *total, ULONG length,
enum server_fd_type type, BOOL avail_mode)
{
- int result;
+ struct msghdr msg;
+ struct iovec iov;
+ int pipe_flags = 0, result;
+
+ if (type == FD_TYPE_PIPE)
+ pipe_flags = get_pipe_flags( fd );
+
for(;;)
{
- result = read( fd, buf + *total, length - *total );
+ if (pipe_flags & NAMED_PIPE_MESSAGE_STREAM_WRITE)
+ {
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+
+ iov.iov_base = buf + *total;
+ iov.iov_len = length - *total;
+
+ result = recvmsg( fd, &msg, MSG_PEEK | (*total ? MSG_DONTWAIT : 0) );
+ if (result >= 0 && !(msg.msg_flags & MSG_TRUNC))
+ {
+ int ret;
+ while (!(ret = recv( fd, NULL, 0, MSG_TRUNC)) && result > 0);
+ if (ret < 0) ERR("dequeue message failed reason: %s\n", strerror(errno));
+ }
+ }
+ else
+ result = read( fd, buf + *total, length - *total );
+
if (result >= 0)
{
*total += result;
- if (!result || *total >= length || avail_mode)
+ if (!result || *total >= length || (avail_mode && !(pipe_flags & NAMED_PIPE_MESSAGE_STREAM_WRITE)))
{
if (*total)
return STATUS_SUCCESS;
@@ -462,16 +505,17 @@ static NTSTATUS read_unix_fd(int fd, char *buf, ULONG *total, ULONG length,
return STATUS_PIPE_BROKEN;
}
}
+ else if (pipe_flags & NAMED_PIPE_MESSAGE_STREAM_WRITE)
+ continue;
else if (type != FD_TYPE_FILE) /* no async I/O on regular files */
return STATUS_PENDING;
}
+ else if (errno == EAGAIN)
+ return (avail_mode && *total) ? STATUS_SUCCESS : STATUS_PENDING;
else if (errno != EINTR)
- {
- if (errno == EAGAIN) break;
return FILE_GetNtStatus();
- }
}
- return STATUS_PENDING;
+ return STATUS_UNSUCCESSFUL; /* never reached */
}
/***********************************************************************
@@ -929,13 +973,14 @@ NTSTATUS WINAPI NtReadFileScatter( HANDLE file, HANDLE event, PIO_APC_ROUTINE ap
/* helper function for NtWriteFile and FILE_AsyncWriteService */
static NTSTATUS write_unix_fd(int fd, const char *buf, ULONG *total, ULONG length, enum server_fd_type type)
{
+ ULONG msgsize = (ULONG)-1;
int result;
for(;;)
{
if (!length && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET))
result = send( fd, buf, 0, 0 );
else
- result = write( fd, buf + *total, length - *total );
+ result = write( fd, buf + *total, min(length - *total, msgsize) );
if (result >= 0)
{
*total += result;
@@ -944,6 +989,17 @@ static NTSTATUS write_unix_fd(int fd, const char *buf, ULONG *total, ULONG lengt
else if (type != FD_TYPE_FILE) /* no async I/O on regular files */
return STATUS_PENDING;
}
+ else if (errno == EMSGSIZE && type == FD_TYPE_PIPE && msgsize > 4096)
+ {
+ static ULONG warn_msgsize;
+ if (msgsize == (ULONG)-1) msgsize = (length + 32 + 4095) & ~4095;
+ if (msgsize > warn_msgsize)
+ {
+ FIXME("Message is too big, try to increase /proc/sys/net/core/wmem_default to at least %d\n", msgsize);
+ warn_msgsize = msgsize;
+ }
+ msgsize -= 4096; /* FIXME: use more intelligent algorithm to discover msgsize */
+ }
else if (errno != EINTR)
{
if (errno == EAGAIN)
@@ -1577,20 +1633,40 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc
status = unix_fd_avail( fd, &avail );
if (!status)
{
+ ULONG data_size = out_size - FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
+ int pipe_flags = get_pipe_flags( fd );
+
buffer->NamedPipeState = 0; /* FIXME */
buffer->ReadDataAvailable = avail;
- buffer->NumberOfMessages = 0; /* FIXME */
- buffer->MessageLength = 0; /* FIXME */
+ buffer->NumberOfMessages = 0;
+ buffer->MessageLength = 0;
io->Information = FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
- if (avail)
+
+ if (pipe_flags & NAMED_PIPE_MESSAGE_STREAM_WRITE)
{
- ULONG data_size = out_size - FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data );
- if (data_size)
+ int peek_offset;
+ socklen_t sock_opt_len = sizeof(peek_offset);
+ if (getsockopt( fd, SOL_SOCKET, SO_PEEK_OFF, &peek_offset, &sock_opt_len ))
+ ERR("getsockopt(SO_PEEK_OFF) failed reason: %s\n", strerror(errno));
+ else
{
- int res = recv( fd, buffer->Data, data_size, MSG_PEEK );
- if (res >= 0) io->Information += res;
+ char *data = data_size ? buffer->Data : NULL;
+ int res = recv( fd, data, data_size, MSG_PEEK | MSG_TRUNC | MSG_DONTWAIT );
+ if (res >= 0) io->Information += min(res, data_size);
+
+ if (setsockopt( fd, SOL_SOCKET, SO_PEEK_OFF, &peek_offset, sizeof(peek_offset) ))
+ ERR("setsockopt(SO_PEEK_OFF) failed reason: %s\n", strerror(errno));
+
+ buffer->ReadDataAvailable = avail - peek_offset;
+ buffer->NumberOfMessages = avail > peek_offset; /* FIXME */
+ buffer->MessageLength = max(0, res);
}
}
+ else if (avail && data_size)
+ {
+ int res = recv( fd, buffer->Data, data_size, MSG_PEEK | MSG_DONTWAIT );
+ if (res >= 0) io->Information += res;
+ }
}
if (needs_close) close( fd );
}
diff --git a/server/named_pipe.c b/server/named_pipe.c
index 81741de..0631159 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -42,6 +42,10 @@
#include <poll.h>
#endif
+#ifndef SO_PEEK_OFF
+#define SO_PEEK_OFF 42
+#endif
+
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
@@ -49,6 +53,7 @@
#include "winioctl.h"
#include "file.h"
+#include "sock.h"
#include "handle.h"
#include "thread.h"
#include "request.h"
@@ -804,14 +809,36 @@ static struct pipe_server *find_available_server( struct named_pipe *pipe )
return NULL;
}
+/* check if message mode named pipes are supported */
+static int check_messagemode(void)
+{
+#ifdef __linux__
+ static const int zero = 0;
+ static int messagemode = -1;
+ int fd;
+
+ if (messagemode < 0)
+ {
+ fd = socket( PF_UNIX, SOCK_SEQPACKET, 0 );
+ messagemode = (fd != -1) && (setsockopt( fd, SOL_SOCKET, SO_PEEK_OFF, &zero, sizeof(zero) ) != -1);
+ if (fd != -1) close( fd );
+ }
+
+ return messagemode;
+#else
+ return 0;
+#endif
+}
+
static struct object *named_pipe_open_file( struct object *obj, unsigned int access,
unsigned int sharing, unsigned int options )
{
+ static const int zero = 0;
struct named_pipe *pipe = (struct named_pipe *)obj;
struct pipe_server *server;
struct pipe_client *client;
unsigned int pipe_sharing;
- int fds[2];
+ int fds[2], type;
if (!(server = find_available_server( pipe )))
{
@@ -830,7 +857,10 @@ static struct object *named_pipe_open_file( struct object *obj, unsigned int acc
if ((client = create_pipe_client( options, pipe->flags )))
{
- if (!socketpair( PF_UNIX, SOCK_STREAM, 0, fds ))
+ type = ((pipe->flags & NAMED_PIPE_MESSAGE_STREAM_WRITE) && check_messagemode()) ?
+ SOCK_SEQPACKET : SOCK_STREAM;
+
+ if (!socketpair( PF_UNIX, type, 0, fds ))
{
assert( !server->fd );
@@ -840,32 +870,53 @@ static struct object *named_pipe_open_file( struct object *obj, unsigned int acc
if (is_overlapped( options )) fcntl( fds[1], F_SETFL, O_NONBLOCK );
if (is_overlapped( server->options )) fcntl( fds[0], F_SETFL, O_NONBLOCK );
- if (pipe->insize)
- {
- setsockopt( fds[0], SOL_SOCKET, SO_RCVBUF, &pipe->insize, sizeof(pipe->insize) );
- setsockopt( fds[1], SOL_SOCKET, SO_RCVBUF, &pipe->insize, sizeof(pipe->insize) );
- }
- if (pipe->outsize)
+ /* FIXME: For message mode we don't pay attention to the provided buffer size.
+ * Linux pipes cannot dynamically adjust size, so we leave the size to the system
+ * instead of using the application provided value. Please note that this will
+ * have the effect that the application doesn't block when sending very large
+ * messages. */
+ if (type != SOCK_SEQPACKET)
{
- setsockopt( fds[0], SOL_SOCKET, SO_SNDBUF, &pipe->outsize, sizeof(pipe->outsize) );
- setsockopt( fds[1], SOL_SOCKET, SO_SNDBUF, &pipe->outsize, sizeof(pipe->outsize) );
+ if (pipe->insize)
+ {
+ setsockopt( fds[0], SOL_SOCKET, SO_RCVBUF, &pipe->insize, sizeof(pipe->insize) );
+ setsockopt( fds[1], SOL_SOCKET, SO_RCVBUF, &pipe->insize, sizeof(pipe->insize) );
+ }
+ if (pipe->outsize)
+ {
+ setsockopt( fds[0], SOL_SOCKET, SO_SNDBUF, &pipe->outsize, sizeof(pipe->outsize) );
+ setsockopt( fds[1], SOL_SOCKET, SO_SNDBUF, &pipe->outsize, sizeof(pipe->outsize) );
+ }
}
- client->fd = create_anonymous_fd( &pipe_client_fd_ops, fds[1], &client->obj, options );
- server->fd = create_anonymous_fd( &pipe_server_fd_ops, fds[0], &server->obj, server->options );
- if (client->fd && server->fd)
+ if (type != SOCK_SEQPACKET || (setsockopt( fds[0], SOL_SOCKET, SO_PEEK_OFF, &zero, sizeof(zero) ) != -1 &&
+ setsockopt( fds[1], SOL_SOCKET, SO_PEEK_OFF, &zero, sizeof(zero) ) != -1))
{
- allow_fd_caching( client->fd );
- allow_fd_caching( server->fd );
- fd_copy_completion( server->ioctl_fd, server->fd );
- if (server->state == ps_wait_open)
- fd_async_wake_up( server->ioctl_fd, ASYNC_TYPE_WAIT, STATUS_SUCCESS );
- set_server_state( server, ps_connected_server );
- server->client = client;
- client->server = server;
+ fcntl( fds[0], F_SETSIG, server->pipe_flags );
+ fcntl( fds[1], F_SETSIG, client->pipe_flags );
+
+ client->fd = create_anonymous_fd( &pipe_client_fd_ops, fds[1], &client->obj, options );
+ server->fd = create_anonymous_fd( &pipe_server_fd_ops, fds[0], &server->obj, server->options );
+ if (client->fd && server->fd)
+ {
+ allow_fd_caching( client->fd );
+ allow_fd_caching( server->fd );
+ fd_copy_completion( server->ioctl_fd, server->fd );
+ if (server->state == ps_wait_open)
+ fd_async_wake_up( server->ioctl_fd, ASYNC_TYPE_WAIT, STATUS_SUCCESS );
+ set_server_state( server, ps_connected_server );
+ server->client = client;
+ client->server = server;
+ }
+ else
+ {
+ release_object( client );
+ client = NULL;
+ }
}
else
{
+ sock_set_error();
release_object( client );
client = NULL;
}
@@ -965,7 +1016,10 @@ DECL_HANDLER(create_named_pipe)
return;
}
- reply->flags = req->flags & ~(NAMED_PIPE_MESSAGE_STREAM_WRITE | NAMED_PIPE_MESSAGE_STREAM_READ);
+ reply->flags = req->flags;
+ if (!check_messagemode())
+ reply->flags &= ~(NAMED_PIPE_MESSAGE_STREAM_WRITE | NAMED_PIPE_MESSAGE_STREAM_READ);
+
reply->handle = 0;
if (!objattr_is_valid( objattr, get_req_data_size() ))
@@ -1065,6 +1119,7 @@ DECL_HANDLER(set_named_pipe_info)
{
struct pipe_server *server;
struct pipe_client *client = NULL;
+ int unix_fd;
server = get_pipe_server_obj( current->process, req->handle, FILE_WRITE_ATTRIBUTES );
if (!server)
@@ -1087,10 +1142,20 @@ DECL_HANDLER(set_named_pipe_info)
else if (client)
{
client->pipe_flags = server->pipe->flags | req->flags;
+ #ifdef __linux__
+ if (client->fd && (unix_fd = get_unix_fd( client->fd )) != -1)
+ fcntl( unix_fd, F_SETSIG, client->pipe_flags );
+ clear_error();
+ #endif
}
else
{
server->pipe_flags = server->pipe->flags | req->flags;
+ #ifdef __linux__
+ if (server->fd && (unix_fd = get_unix_fd( server->fd )) != -1)
+ fcntl( unix_fd, F_SETSIG, server->pipe_flags );
+ clear_error();
+ #endif
}
if (client)
diff --git a/server/sock.c b/server/sock.c
index 7c0212e..73a2549 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -55,6 +55,7 @@
#include "process.h"
#include "file.h"
+#include "sock.h"
#include "handle.h"
#include "thread.h"
#include "request.h"
@@ -127,7 +128,6 @@ static void sock_cancel_async( struct fd *fd, struct process *process, struct th
static int sock_get_ntstatus( int err );
static int sock_get_error( int err );
-static void sock_set_error(void);
static const struct object_ops sock_ops =
{
@@ -910,7 +910,7 @@ static int sock_get_ntstatus( int err )
}
/* set the last error depending on errno */
-static void sock_set_error(void)
+void sock_set_error(void)
{
set_error( sock_get_ntstatus( errno ) );
}
diff --git a/server/sock.h b/server/sock.h
new file mode 100644
index 0000000..21551b4
--- /dev/null
+++ b/server/sock.h
@@ -0,0 +1,26 @@
+/*
+ * Server-side socket definitions
+ *
+ * Copyright (C) 2014 Sebastian Lackner
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_SERVER_SOCK_H
+#define __WINE_SERVER_SOCK_H
+
+extern void sock_set_error(void);
+
+#endif /* __WINE_SERVER_SOCK_H */
--
2.1.3

View File

@ -0,0 +1,321 @@
From 8d70c149974dafbdabc76cf2fb9daf9108a853f2 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Mon, 11 Aug 2014 18:20:52 +0200
Subject: ntdll: Add handling for partially received messages in NtReadFile.
Changes in v2:
* Merged with final version of error code handling.
* Poll for broken pipe to distinguish between zero-byte messages and errors.
Changes in v3:
* Rebased. Simplified check for broken pipe.
Changes in v4:
* Include changes from later patch.
---
dlls/kernel32/tests/pipe.c | 53 +++++-----------------------------------------
dlls/ntdll/file.c | 28 ++++++++++++++++++------
2 files changed, 27 insertions(+), 54 deletions(-)
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c
index 743144e..6a27826 100644
--- a/dlls/kernel32/tests/pipe.c
+++ b/dlls/kernel32/tests/pipe.c
@@ -304,9 +304,7 @@ static void test_CreateNamedPipe(int pipemode)
else
{
SetLastError(0xdeadbeef);
- todo_wine
ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile\n");
- todo_wine
ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n");
}
ok(readden == 4, "read got %d bytes\n", readden);
@@ -327,15 +325,11 @@ static void test_CreateNamedPipe(int pipemode)
else
{
SetLastError(0xdeadbeef);
- todo_wine
ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile\n");
- todo_wine
ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n");
ok(readden == 4, "read got %d bytes\n", readden);
SetLastError(0xdeadbeef);
- todo_wine
ok(!ReadFile(hnp, ibuf + 4, 4, &readden, NULL), "ReadFile\n");
- todo_wine
ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n");
}
ok(readden == 4, "read got %d bytes\n", readden);
@@ -397,9 +391,7 @@ static void test_CreateNamedPipe(int pipemode)
ok(readden == sizeof(obuf) + sizeof(obuf2), "read 4 got %d bytes\n", readden);
}
else {
- todo_wine {
- ok(readden == sizeof(obuf), "read 4 got %d bytes\n", readden);
- }
+ ok(readden == sizeof(obuf), "read 4 got %d bytes\n", readden);
}
pbuf = ibuf;
ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 4a check\n");
@@ -429,9 +421,7 @@ static void test_CreateNamedPipe(int pipemode)
pbuf = ibuf;
ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 5a check\n");
ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
- todo_wine {
- ok(readden == sizeof(obuf), "read 5 got %d bytes\n", readden);
- }
+ ok(readden == sizeof(obuf), "read 5 got %d bytes\n", readden);
pbuf = ibuf;
ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 5a check\n");
if (readden <= sizeof(obuf))
@@ -440,10 +430,8 @@ static void test_CreateNamedPipe(int pipemode)
/* Multiple writes in the reverse direction */
/* the write of obuf2 from write4 should still be in the buffer */
ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek6a\n");
- todo_wine {
- ok(readden == sizeof(obuf2), "peek6a got %d bytes\n", readden);
- ok(avail == sizeof(obuf2), "peek6a got %d bytes available\n", avail);
- }
+ ok(readden == sizeof(obuf2), "peek6a got %d bytes\n", readden);
+ ok(avail == sizeof(obuf2), "peek6a got %d bytes available\n", avail);
if (avail > 0) {
ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
ok(readden == sizeof(obuf2), "read 6a got %d bytes\n", readden);
@@ -461,9 +449,7 @@ static void test_CreateNamedPipe(int pipemode)
pbuf = ibuf;
ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 6a check\n");
ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
- todo_wine {
- ok(readden == sizeof(obuf), "read 6b got %d bytes\n", readden);
- }
+ ok(readden == sizeof(obuf), "read 6b got %d bytes\n", readden);
pbuf = ibuf;
ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 6a check\n");
if (readden <= sizeof(obuf))
@@ -474,9 +460,7 @@ static void test_CreateNamedPipe(int pipemode)
ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), "WriteFile 7\n");
ok(written == sizeof(obuf2), "write file len 7\n");
SetLastError(0xdeadbeef);
- todo_wine
ok(!ReadFile(hFile, ibuf, 4, &readden, NULL), "ReadFile 7\n");
- todo_wine
ok(GetLastError() == ERROR_MORE_DATA, "wrong error 7\n");
ok(readden == 4, "read got %d bytes 7\n", readden);
ok(ReadFile(hFile, ibuf + 4, sizeof(ibuf) - 4, &readden, NULL), "ReadFile 7\n");
@@ -487,9 +471,7 @@ static void test_CreateNamedPipe(int pipemode)
ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile 8\n");
ok(written == sizeof(obuf), "write file len 8\n");
SetLastError(0xdeadbeef);
- todo_wine
ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile 8\n");
- todo_wine
ok(GetLastError() == ERROR_MORE_DATA, "wrong error 8\n");
ok(readden == 4, "read got %d bytes 8\n", readden);
ok(ReadFile(hnp, ibuf + 4, sizeof(ibuf) - 4, &readden, NULL), "ReadFile 8\n");
@@ -514,16 +496,12 @@ static void test_CreateNamedPipe(int pipemode)
ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 9\n", readden);
ok(leftmsg == sizeof(obuf), "peek got %d bytes left in message 9\n", leftmsg);
SetLastError(0xdeadbeef);
- todo_wine
ok(!ReadFile(hFile, ibuf, 4, &readden, NULL), "ReadFile 9\n");
- todo_wine
ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n");
ok(readden == 4, "read got %d bytes 9\n", readden);
SetLastError(0xdeadbeef);
ret = RpcReadFile(hFile, ibuf + 4, 4, &readden, NULL);
- todo_wine
ok(!ret, "RpcReadFile 9\n");
- todo_wine
ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n");
ok(readden == 4, "read got %d bytes 9\n", readden);
readden = leftmsg = -1;
@@ -536,7 +514,6 @@ static void test_CreateNamedPipe(int pipemode)
ok(leftmsg == sizeof(obuf) - 8, "peek got %d bytes left in message 9\n", leftmsg);
ret = RpcReadFile(hFile, ibuf + 8, sizeof(ibuf), &readden, NULL);
ok(ret, "RpcReadFile 9\n");
- todo_wine
ok(readden == sizeof(obuf) - 8, "read got %d bytes 9\n", readden);
ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check 9\n");
if (readden <= sizeof(obuf) - 8) /* blocks forever if second part was already received */
@@ -553,13 +530,10 @@ static void test_CreateNamedPipe(int pipemode)
SetLastError(0xdeadbeef);
ret = RpcReadFile(hFile, ibuf, 4, &readden, NULL);
ok(!ret, "RpcReadFile 9\n");
- todo_wine
ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n");
ok(readden == 4, "read got %d bytes 9\n", readden);
SetLastError(0xdeadbeef);
- todo_wine
ok(!ReadFile(hFile, ibuf + 4, 4, &readden, NULL), "ReadFile 9\n");
- todo_wine
ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n");
ok(readden == 4, "read got %d bytes 9\n", readden);
readden = leftmsg = -1;
@@ -599,16 +573,12 @@ static void test_CreateNamedPipe(int pipemode)
ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 10\n", readden);
ok(leftmsg == sizeof(obuf2), "peek got %d bytes left in message 10\n", leftmsg);
SetLastError(0xdeadbeef);
- todo_wine
ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile 10\n");
- todo_wine
ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n");
ok(readden == 4, "read got %d bytes 10\n", readden);
SetLastError(0xdeadbeef);
ret = RpcReadFile(hnp, ibuf + 4, 4, &readden, NULL);
- todo_wine
ok(!ret, "RpcReadFile 10\n");
- todo_wine
ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n");
ok(readden == 4, "read got %d bytes 10\n", readden);
readden = leftmsg = -1;
@@ -621,7 +591,6 @@ static void test_CreateNamedPipe(int pipemode)
ok(leftmsg == sizeof(obuf2) - 8, "peek got %d bytes left in message 10\n", leftmsg);
ret = RpcReadFile(hnp, ibuf + 8, sizeof(ibuf), &readden, NULL);
ok(ret, "RpcReadFile 10\n");
- todo_wine
ok(readden == sizeof(obuf2) - 8, "read got %d bytes 10\n", readden);
ok(memcmp(obuf2, ibuf, sizeof(obuf2)) == 0, "content check 10\n");
if (readden <= sizeof(obuf2) - 8) /* blocks forever if second part was already received */
@@ -638,13 +607,10 @@ static void test_CreateNamedPipe(int pipemode)
SetLastError(0xdeadbeef);
ret = RpcReadFile(hnp, ibuf, 4, &readden, NULL);
ok(!ret, "RpcReadFile 10\n");
- todo_wine
ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n");
ok(readden == 4, "read got %d bytes 10\n", readden);
SetLastError(0xdeadbeef);
- todo_wine
ok(!ReadFile(hnp, ibuf + 4, 4, &readden, NULL), "ReadFile 10\n");
- todo_wine
ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n");
ok(readden == 4, "read got %d bytes 10\n", readden);
readden = leftmsg = -1;
@@ -750,15 +716,11 @@ static void test_CreateNamedPipe(int pipemode)
else
{
SetLastError(0xdeadbeef);
- todo_wine
ok(!ReadFile(hFile, big_ibuf, 32, &readden, NULL), "ReadFile\n");
- todo_wine
ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n");
ok(readden == 32, "read got %d bytes\n", readden);
SetLastError(0xdeadbeef);
- todo_wine
ok(!ReadFile(hFile, big_ibuf + 32, 32, &readden, NULL), "ReadFile\n");
- todo_wine
ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n");
}
ok(readden == 32, "read got %d bytes\n", readden);
@@ -948,7 +910,6 @@ static void test_CloseNamedPipe(void)
/* close server end without disconnecting */
ok(CloseHandle(hnp), "CloseHandle() failed: %08x\n", GetLastError());
- todo_wine
ok(ReadFile(hFile, ibuf, 0, &readden, NULL), "ReadFile() failed: %08x\n", GetLastError());
ok(readden == 0, "got %d bytes\n", readden);
@@ -990,7 +951,6 @@ static void test_CloseNamedPipe(void)
ok(CloseHandle(hFile), "CloseHandle() failed: %08x\n", GetLastError());
/* you'd think ERROR_MORE_DATA, but no */
- todo_wine
ok(ReadFile(hnp, ibuf, 0, &readden, NULL), "ReadFile() failed: %08x\n", GetLastError());
ok(readden == 0, "got %d bytes\n", readden);
@@ -2460,7 +2420,6 @@ static void test_readfileex_pending(void)
num_bytes = 0xdeadbeef;
SetLastError(0xdeadbeef);
ret = ReadFile(server, read_buf, 0, &num_bytes, &overlapped);
-todo_wine
ok(GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %d\n", GetLastError());
ok(num_bytes == 0, "bytes %u\n", num_bytes);
ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal);
@@ -2476,11 +2435,9 @@ todo_wine
ok(num_bytes == 1, "bytes %u\n", num_bytes);
wait = WaitForSingleObject(event, 100);
-todo_wine
ok(wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait);
ok(num_bytes == 1, "bytes %u\n", num_bytes);
-todo_wine
ok((NTSTATUS)overlapped.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", overlapped.Internal);
ok(overlapped.InternalHigh == 0, "expected 0, got %lu\n", overlapped.InternalHigh);
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 5cbfa40..81f941d 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -415,7 +415,7 @@ NTSTATUS FILE_GetNtStatus(void)
}
}
-/* helper function for FSCTL_PIPE_PEEK */
+/* helper function for FSCTL_PIPE_PEEK and read_unix_fd */
static NTSTATUS unix_fd_avail(int fd, int *avail)
{
struct pollfd pollfd;
@@ -444,7 +444,14 @@ static NTSTATUS unix_fd_avail(int fd, int *avail)
static inline int get_pipe_flags(int fd)
{
#ifdef __linux__
- return fcntl( fd, F_GETSIG );
+ int flags = fcntl( fd, F_GETSIG );
+
+ /* NAMED_PIPE_MESSAGE_STREAM_READ only allowed in
+ * combination with NAMED_PIPE_MESSAGE_STREAM_WRITE. */
+ if (!(flags & NAMED_PIPE_MESSAGE_STREAM_WRITE))
+ flags &= ~NAMED_PIPE_MESSAGE_STREAM_READ;
+
+ return flags;
#else
return 0;
#endif
@@ -490,10 +497,12 @@ static NTSTATUS read_unix_fd(int fd, char *buf, ULONG *total, ULONG length,
if (result >= 0)
{
*total += result;
- if (!result || *total >= length || (avail_mode && !(pipe_flags & NAMED_PIPE_MESSAGE_STREAM_WRITE)))
+ if (!result || *total >= length || (avail_mode && !(pipe_flags & NAMED_PIPE_MESSAGE_STREAM_WRITE)) ||
+ ((pipe_flags & NAMED_PIPE_MESSAGE_STREAM_READ) && !(msg.msg_flags & MSG_TRUNC)))
{
if (*total)
- return STATUS_SUCCESS;
+ return ((pipe_flags & NAMED_PIPE_MESSAGE_STREAM_READ) && (msg.msg_flags & MSG_TRUNC)) ?
+ STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
switch (type)
{
case FD_TYPE_FILE:
@@ -501,11 +510,18 @@ static NTSTATUS read_unix_fd(int fd, char *buf, ULONG *total, ULONG length,
return length ? STATUS_END_OF_FILE : STATUS_SUCCESS;
case FD_TYPE_SERIAL:
return STATUS_PENDING;
+ case FD_TYPE_PIPE:
+ {
+ NTSTATUS status = unix_fd_avail( fd, &result );
+ if (!status && !result && !length) status = STATUS_PENDING;
+ return status;
+ }
default:
return STATUS_PIPE_BROKEN;
}
}
- else if (pipe_flags & NAMED_PIPE_MESSAGE_STREAM_WRITE)
+ else if ((pipe_flags & (NAMED_PIPE_MESSAGE_STREAM_WRITE | NAMED_PIPE_MESSAGE_STREAM_READ)) ==
+ NAMED_PIPE_MESSAGE_STREAM_WRITE)
continue;
else if (type != FD_TYPE_FILE) /* no async I/O on regular files */
return STATUS_PENDING;
@@ -863,7 +879,7 @@ done:
err:
if (needs_close) close( unix_handle );
- if (status == STATUS_SUCCESS || (status == STATUS_END_OF_FILE && !async_read))
+ if (status == STATUS_SUCCESS || status == STATUS_BUFFER_OVERFLOW || (status == STATUS_END_OF_FILE && !async_read))
{
io_status->u.Status = status;
io_status->Information = total;
--
2.1.3

View File

@ -0,0 +1,188 @@
From d94857ffb00c9e24dcaff68aed1e14a6b99745f5 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sun, 17 Aug 2014 00:47:26 +0200
Subject: kernel32/tests: Add more tests with overlapped IO and partial reads
from named pipes.
---
dlls/kernel32/tests/pipe.c | 150 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 150 insertions(+)
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c
index 6a27826..ba49974 100644
--- a/dlls/kernel32/tests/pipe.c
+++ b/dlls/kernel32/tests/pipe.c
@@ -2300,6 +2300,7 @@ static void test_readfileex_pending(void)
OVERLAPPED overlapped;
char read_buf[1024];
char write_buf[1024];
+ const char long_test_string[] = "12test3456ab";
const char test_string[] = "test";
int i;
@@ -2339,6 +2340,9 @@ static void test_readfileex_pending(void)
ret = ReadFileEx(server, read_buf, sizeof(read_buf), &overlapped, completion_routine);
ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError());
ok(completion_called == 0, "completion routine called before ReadFileEx returned\n");
+ wait = WaitForSingleObject(event, 100);
+ ok(wait == WAIT_TIMEOUT, "WaitForSingleObjectEx returned %x\n", wait);
+ ok(completion_called == 0, "completion routine called before WriteFile started\n");
ret = WriteFile(client, test_string, strlen(test_string), &num_bytes, NULL);
ok(ret == TRUE, "WriteFile failed\n");
@@ -2449,6 +2453,152 @@ todo_wine
CloseHandle(client);
CloseHandle(server);
+
+ server = CreateNamedPipeA(PIPENAME, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX,
+ /* dwOpenMode */ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+ /* nMaxInstances */ 1,
+ /* nOutBufSize */ 1024,
+ /* nInBufSize */ 1024,
+ /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+ /* lpSecurityAttrib */ NULL);
+ ok(server != INVALID_HANDLE_VALUE, "cf failed\n");
+
+ client = CreateFileA(PIPENAME, GENERIC_READ|GENERIC_WRITE, 0, NULL,
+ OPEN_EXISTING, 0, NULL);
+ ok(client != INVALID_HANDLE_VALUE, "cf failed\n");
+
+ memset(&overlapped, 0, sizeof(overlapped));
+ overlapped.hEvent = event;
+
+ /* Start a call to ReadFileEx which cannot complete immediately */
+ memset(read_buf, 0, sizeof(read_buf));
+ completion_called = 0;
+ ResetEvent(event);
+ ret = ReadFileEx(server, read_buf, 4, &overlapped, completion_routine);
+ ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError());
+ ok(completion_called == 0, "completion routine called before ReadFileEx returned\n");
+ wait = WaitForSingleObject(event, 100);
+ ok(wait == WAIT_TIMEOUT, "WaitForSingleObject returned %x\n", wait);
+ ok(completion_called == 0, "completion routine called before WriteFile started\n");
+
+ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
+ ok(ret == TRUE, "WriteFile failed\n");
+ ok(num_bytes == strlen(long_test_string), "only %i bytes written\n", num_bytes);
+ ok(completion_called == 0, "completion routine called during WriteFile\n");
+ wait = WaitForSingleObjectEx(event, 0, TRUE);
+ ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait);
+
+ ok(completion_called == 1, "completion not called after writing pipe\n");
+ todo_wine
+ ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode);
+ ok(completion_num_bytes == 4, "ReadFileEx returned only %d bytes\n", completion_num_bytes);
+ ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n");
+ ok(!memcmp(long_test_string, read_buf, 4), "ReadFileEx read wrong bytes\n");
+
+ ret = ReadFile(server, read_buf + 4, 4, &num_bytes, NULL);
+ ok(ret == FALSE, "ReadFile succeeded\n");
+ ok(num_bytes == 4, "ReadFile returned only %d bytes\n", num_bytes);
+ ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n");
+ ret = ReadFile(server, read_buf + 8, sizeof(read_buf) - 8, &num_bytes, NULL);
+ ok(ret == TRUE, "ReadFile failed\n");
+ ok(num_bytes == strlen(long_test_string)-8, "ReadFile returned only %d bytes\n", num_bytes);
+ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+
+ /* Call ReadFileEx when there is already some content in the pipe */
+ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
+ ok(ret == TRUE, "WriteFile failed\n");
+ ok(num_bytes == strlen(long_test_string), "only %i bytes written\n", num_bytes);
+
+ memset(read_buf, 0, sizeof(read_buf));
+ completion_called = 0;
+ ResetEvent(event);
+ ret = ReadFileEx(server, read_buf, 4, &overlapped, completion_routine);
+ todo_wine
+ ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError());
+ ok(completion_called == 0, "completion routine called before ReadFileEx returned\n");
+ wait = WaitForSingleObjectEx(event, 0, TRUE);
+ todo_wine
+ ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait);
+ todo_wine
+ ok(completion_called == 1, "completion not called after writing pipe\n");
+ todo_wine
+ ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode);
+ ok(completion_num_bytes == 4, "ReadFileEx returned only %d bytes\n", completion_num_bytes);
+ ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n");
+ ok(!memcmp(long_test_string, read_buf, 4), "ReadFileEx read wrong bytes\n");
+
+ ret = ReadFile(server, read_buf + 4, sizeof(read_buf) - 4, &num_bytes, NULL);
+ ok(ret == TRUE, "ReadFile failed\n");
+ ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes);
+ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+
+ /* Check content of overlapped structure */
+ memset(read_buf, 0, sizeof(read_buf));
+ S(U(overlapped)).Offset = 0;
+ S(U(overlapped)).OffsetHigh = 0;
+ overlapped.Internal = -1;
+ overlapped.InternalHigh = -1;
+ overlapped.hEvent = event;
+ num_bytes = 0xdeadbeef;
+ SetLastError(0xdeadbeef);
+ ret = ReadFile(server, read_buf, 4, &num_bytes, &overlapped);
+ ok(GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %d\n", GetLastError());
+ ok(num_bytes == 0, "bytes %u\n", num_bytes);
+ ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal);
+ todo_wine
+ ok(overlapped.InternalHigh == -1, "expected -1, got %lu\n", overlapped.InternalHigh);
+ wait = WaitForSingleObject(event, 100);
+ ok(wait == WAIT_TIMEOUT, "WaitForSingleObject returned %x\n", wait);
+ ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal);
+
+ num_bytes = 0xdeadbeef;
+ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
+ ok(ret, "WriteFile failed\n");
+ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+ wait = WaitForSingleObject(event, 100);
+ ok(wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait);
+ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+ ok((NTSTATUS)overlapped.Internal == STATUS_BUFFER_OVERFLOW, "expected STATUS_BUFFER_OVERFLOW, got %#lx\n", overlapped.Internal);
+ ok(overlapped.InternalHigh == 4, "expected 4, got %lu\n", overlapped.InternalHigh);
+
+ ret = ReadFile(server, read_buf + 4, sizeof(read_buf) - 4, &num_bytes, NULL);
+ ok(ret == TRUE, "ReadFile failed\n");
+ ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes);
+ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+
+ /* Call ReadFile when there is already some content in the pipe */
+ num_bytes = 0xdeadbeef;
+ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
+ ok(ret, "WriteFile failed\n");
+ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+
+ memset(read_buf, 0, sizeof(read_buf));
+ S(U(overlapped)).Offset = 0;
+ S(U(overlapped)).OffsetHigh = 0;
+ overlapped.Internal = -1;
+ overlapped.InternalHigh = -1;
+ overlapped.hEvent = event;
+ num_bytes = 0xdeadbeef;
+ SetLastError(0xdeadbeef);
+ ret = ReadFile(server, read_buf, 4, &num_bytes, &overlapped);
+ ok(ret == FALSE, "ReadFile succeeded\n");
+ ok(GetLastError() == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", GetLastError());
+ todo_wine
+ ok(num_bytes == 0, "ReadFile returned %d bytes\n", num_bytes);
+ wait = WaitForSingleObjectEx(event, 0, TRUE);
+ ok(wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait);
+ todo_wine
+ ok(num_bytes == 0, "bytes %u\n", num_bytes);
+ ok((NTSTATUS)overlapped.Internal == STATUS_BUFFER_OVERFLOW, "expected STATUS_BUFFER_OVERFLOW, got %#lx\n", overlapped.Internal);
+ ok(overlapped.InternalHigh == 4, "expected 4, got %lu\n", overlapped.InternalHigh);
+
+ ret = ReadFile(server, read_buf + 4, sizeof(read_buf) - 4, &num_bytes, NULL);
+ ok(ret == TRUE, "ReadFile failed\n");
+ ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes);
+ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+
+ CloseHandle(client);
+ CloseHandle(server);
CloseHandle(event);
}
--
2.1.3

View File

@ -0,0 +1,85 @@
From 87e6095901f7405efc256997f1e1d6f0338ab2b5 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sun, 17 Aug 2014 01:13:44 +0200
Subject: ntdll: Fix some tests for overlapped partial reads.
Windows also sends as APC user notification for STATUS_BUFFER_OVERFLOW.
Moreover in some cases STATUS_BUFFER_OVERFLOW is reported as success, not
as failure.
---
dlls/kernel32/file.c | 7 ++++---
dlls/kernel32/tests/pipe.c | 5 -----
dlls/ntdll/file.c | 4 ++--
3 files changed, 6 insertions(+), 10 deletions(-)
diff --git a/dlls/kernel32/file.c b/dlls/kernel32/file.c
index 006db1c..78cfdb7 100644
--- a/dlls/kernel32/file.c
+++ b/dlls/kernel32/file.c
@@ -325,8 +325,9 @@ BOOL WINAPI AreFileApisANSI(void)
static void WINAPI FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG reserved)
{
LPOVERLAPPED_COMPLETION_ROUTINE cr = apc_user;
-
- cr(RtlNtStatusToDosError(io_status->u.Status), io_status->Information, (LPOVERLAPPED)io_status);
+ NTSTATUS status = io_status->u.Status;
+ if (status == STATUS_BUFFER_OVERFLOW) status = STATUS_SUCCESS;
+ cr(RtlNtStatusToDosError(status), io_status->Information, (LPOVERLAPPED)io_status);
}
@@ -358,7 +359,7 @@ BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
io_status, buffer, bytesToRead, &offset, NULL);
- if (status && status != STATUS_PENDING)
+ if (status && status != STATUS_PENDING && status != STATUS_BUFFER_OVERFLOW)
{
SetLastError( RtlNtStatusToDosError(status) );
return FALSE;
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c
index ba49974..53f8f30 100644
--- a/dlls/kernel32/tests/pipe.c
+++ b/dlls/kernel32/tests/pipe.c
@@ -2489,7 +2489,6 @@ todo_wine
ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait);
ok(completion_called == 1, "completion not called after writing pipe\n");
- todo_wine
ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode);
ok(completion_num_bytes == 4, "ReadFileEx returned only %d bytes\n", completion_num_bytes);
ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n");
@@ -2513,15 +2512,11 @@ todo_wine
completion_called = 0;
ResetEvent(event);
ret = ReadFileEx(server, read_buf, 4, &overlapped, completion_routine);
- todo_wine
ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError());
ok(completion_called == 0, "completion routine called before ReadFileEx returned\n");
wait = WaitForSingleObjectEx(event, 0, TRUE);
- todo_wine
ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait);
- todo_wine
ok(completion_called == 1, "completion not called after writing pipe\n");
- todo_wine
ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode);
ok(completion_num_bytes == 4, "ReadFileEx returned only %d bytes\n", completion_num_bytes);
ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n");
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 81f941d..d3f0c0e 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -885,8 +885,8 @@ err:
io_status->Information = total;
TRACE("= SUCCESS (%u)\n", total);
if (hEvent) NtSetEvent( hEvent, NULL );
- if (apc && !status) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
- (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
+ if (apc && status != STATUS_END_OF_FILE) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
+ (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
}
else
{
--
2.1.3

View File

@ -0,0 +1,384 @@
From 186746674015db7533c9b25c8b633c2e3881334e Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Mon, 11 Aug 2014 00:56:46 +0200
Subject: kernel32/tests: Test sending, peeking and receiving an empty message.
Changes in v2:
* As async handling is now working correctly, it breaks some tests :/
We need a lot of ugly code to prevent the tests from deadlocking...
* Fix issue in broken pipe check, should be moved into an earlier patch.
---
dlls/kernel32/tests/pipe.c | 336 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 336 insertions(+)
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c
index 53f8f30..89a13f5 100644
--- a/dlls/kernel32/tests/pipe.c
+++ b/dlls/kernel32/tests/pipe.c
@@ -337,6 +337,146 @@ static void test_CreateNamedPipe(int pipemode)
ok(readden == sizeof(obuf2) - 8, "read got %d bytes\n", readden);
ok(memcmp(obuf2, ibuf, written) == 0, "content check\n");
+ /* Tests for sending empty messages */
+ memset(ibuf, 0, sizeof(ibuf));
+ ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n");
+ ok(written == 0, "write file len\n");
+ if (pipemode != PIPE_TYPE_BYTE)
+ {
+ ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
+ ok(readden == 0, "read got %d bytes\n", readden);
+ }
+
+ memset(ibuf, 0, sizeof(ibuf));
+ ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n");
+ ok(written == 0, "write file len\n");
+ if (pipemode != PIPE_TYPE_BYTE)
+ {
+ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
+ ok(readden == 0, "read got %d bytes\n", readden);
+ }
+
+ /* similar to above, but with an additional call to PeekNamedPipe inbetween */
+ memset(ibuf, 0, sizeof(ibuf));
+ ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n");
+ ok(written == 0, "write file len\n");
+ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL), "Peek\n");
+ ok(readden == 0, "peek got %d bytes\n", readden);
+ if (pipemode != PIPE_TYPE_BYTE)
+ {
+ struct rpcThreadArgs rpcargs;
+ HANDLE thread;
+ DWORD threadId;
+
+ rpcargs.returnValue = 0;
+ rpcargs.lastError = GetLastError();
+ rpcargs.op = RPC_READFILE;
+ rpcargs.args[0] = (ULONG_PTR)hFile;
+ rpcargs.args[1] = (ULONG_PTR)ibuf;
+ rpcargs.args[2] = (ULONG_PTR)sizeof(ibuf);
+ rpcargs.args[3] = (ULONG_PTR)&readden;
+ rpcargs.args[4] = (ULONG_PTR)NULL;
+
+ thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId);
+ ok(thread != NULL, "CreateThread failed. %d\n", GetLastError());
+ ret = WaitForSingleObject(thread, 200);
+ todo_wine
+ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0);
+ if (ret == WAIT_TIMEOUT)
+ {
+ ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n");
+ ok(written == 0, "write file len\n");
+ ret = WaitForSingleObject(thread, 200);
+ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0);
+ }
+ CloseHandle(thread);
+ ok((BOOL)rpcargs.returnValue, "ReadFile\n");
+ ok(readden == 0, "read got %d bytes\n", readden);
+ }
+
+ memset(ibuf, 0, sizeof(ibuf));
+ ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n");
+ ok(written == 0, "write file len\n");
+ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, NULL), "Peek\n");
+ ok(readden == 0, "peek got %d bytes\n", readden);
+ if (pipemode != PIPE_TYPE_BYTE)
+ {
+ struct rpcThreadArgs rpcargs;
+ HANDLE thread;
+ DWORD threadId;
+
+ rpcargs.returnValue = 0;
+ rpcargs.lastError = GetLastError();
+ rpcargs.op = RPC_READFILE;
+ rpcargs.args[0] = (ULONG_PTR)hnp;
+ rpcargs.args[1] = (ULONG_PTR)ibuf;
+ rpcargs.args[2] = (ULONG_PTR)sizeof(ibuf);
+ rpcargs.args[3] = (ULONG_PTR)&readden;
+ rpcargs.args[4] = (ULONG_PTR)NULL;
+
+ thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId);
+ ok(thread != NULL, "CreateThread failed. %d\n", GetLastError());
+ ret = WaitForSingleObject(thread, 200);
+ todo_wine
+ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0);
+ if (ret == WAIT_TIMEOUT)
+ {
+ ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n");
+ ok(written == 0, "write file len\n");
+ ret = WaitForSingleObject(thread, 200);
+ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0);
+ }
+ CloseHandle(thread);
+ ok((BOOL)rpcargs.returnValue, "ReadFile\n");
+ ok(readden == 0, "read got %d bytes\n", readden);
+ }
+
+ /* similar to above, but now with PeekNamedPipe and multiple messages */
+ memset(ibuf, 0, sizeof(ibuf));
+ ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n");
+ ok(written == 0, "write file len\n");
+ ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
+ ok(written == sizeof(obuf), "write file len\n");
+ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "Peek\n");
+ ok(readden == sizeof(obuf), "peek got %d bytes\n", readden);
+ ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg);
+ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "Peek\n");
+ ok(readden == sizeof(obuf), "peek got %d bytes\n", readden);
+ if (pipemode != PIPE_TYPE_BYTE)
+ todo_wine
+ ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg);
+ else
+ ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg);
+ ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
+ ok(readden == sizeof(obuf), "read got %d bytes\n", readden);
+ ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check\n");
+
+ memset(ibuf, 0, sizeof(ibuf));
+ ok(WriteFile(hFile, obuf2, 0, &written, NULL), "WriteFile\n");
+ ok(written == 0, "write file len\n");
+ ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), "WriteFile\n");
+ ok(written == sizeof(obuf2), "write file len\n");
+ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "Peek\n");
+ ok(readden == sizeof(obuf2), "peek got %d bytes\n", readden);
+ ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg);
+ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "Peek\n");
+ ok(readden == sizeof(obuf2), "peek got %d bytes\n", readden);
+ if (pipemode != PIPE_TYPE_BYTE)
+ todo_wine
+ ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg);
+ else
+ ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg);
+ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
+ if (pipemode != PIPE_TYPE_BYTE)
+ {
+ todo_wine
+ ok(readden == 0, "read got %d bytes\n", readden);
+ if (readden == 0)
+ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
+ }
+ ok(readden == sizeof(obuf2), "read got %d bytes\n", readden);
+ ok(memcmp(obuf2, ibuf, sizeof(obuf2)) == 0, "content check\n");
+
/* Test reading of multiple writes */
memset(ibuf, 0, sizeof(ibuf));
ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile3a\n");
@@ -455,6 +595,133 @@ static void test_CreateNamedPipe(int pipemode)
if (readden <= sizeof(obuf))
ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
+ /* Tests for sending empty messages */
+ memset(ibuf, 0, sizeof(ibuf));
+ ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n");
+ ok(written == 0, "write file len\n");
+ ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
+ ok(readden == 0, "read got %d bytes\n", readden);
+
+ memset(ibuf, 0, sizeof(ibuf));
+ ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n");
+ ok(written == 0, "write file len\n");
+ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
+ ok(readden == 0, "read got %d bytes\n", readden);
+
+ /* similar to above, but with an additional call to PeekNamedPipe inbetween */
+ memset(ibuf, 0, sizeof(ibuf));
+ ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n");
+ ok(written == 0, "write file len\n");
+ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL), "Peek\n");
+ ok(readden == 0, "peek got %d bytes\n", readden);
+ {
+ struct rpcThreadArgs rpcargs;
+ HANDLE thread;
+ DWORD threadId;
+
+ rpcargs.returnValue = 0;
+ rpcargs.lastError = GetLastError();
+ rpcargs.op = RPC_READFILE;
+ rpcargs.args[0] = (ULONG_PTR)hFile;
+ rpcargs.args[1] = (ULONG_PTR)ibuf;
+ rpcargs.args[2] = (ULONG_PTR)sizeof(ibuf);
+ rpcargs.args[3] = (ULONG_PTR)&readden;
+ rpcargs.args[4] = (ULONG_PTR)NULL;
+
+ thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId);
+ ok(thread != NULL, "CreateThread failed. %d\n", GetLastError());
+ ret = WaitForSingleObject(thread, 200);
+ todo_wine
+ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0);
+ if (ret == WAIT_TIMEOUT)
+ {
+ ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n");
+ ok(written == 0, "write file len\n");
+ ret = WaitForSingleObject(thread, 200);
+ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0);
+ }
+ CloseHandle(thread);
+ ok((BOOL)rpcargs.returnValue, "ReadFile\n");
+ ok(readden == 0, "read got %d bytes\n", readden);
+ }
+
+ memset(ibuf, 0, sizeof(ibuf));
+ ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n");
+ ok(written == 0, "write file len\n");
+ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, NULL), "Peek\n");
+ ok(readden == 0, "peek got %d bytes\n", readden);
+ {
+ struct rpcThreadArgs rpcargs;
+ HANDLE thread;
+ DWORD threadId;
+
+ rpcargs.returnValue = 0;
+ rpcargs.lastError = GetLastError();
+ rpcargs.op = RPC_READFILE;
+ rpcargs.args[0] = (ULONG_PTR)hnp;
+ rpcargs.args[1] = (ULONG_PTR)ibuf;
+ rpcargs.args[2] = (ULONG_PTR)sizeof(ibuf);
+ rpcargs.args[3] = (ULONG_PTR)&readden;
+ rpcargs.args[4] = (ULONG_PTR)NULL;
+
+ thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId);
+ ok(thread != NULL, "CreateThread failed. %d\n", GetLastError());
+ ret = WaitForSingleObject(thread, 200);
+ todo_wine
+ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0);
+ if (ret == WAIT_TIMEOUT)
+ {
+ ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n");
+ ok(written == 0, "write file len\n");
+ ret = WaitForSingleObject(thread, 200);
+ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0);
+ }
+ CloseHandle(thread);
+ ok((BOOL)rpcargs.returnValue, "ReadFile\n");
+ ok(readden == 0, "read got %d bytes\n", readden);
+ }
+
+ /* similar to above, but now with PeekNamedPipe and multiple messages */
+ memset(ibuf, 0, sizeof(ibuf));
+ ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n");
+ ok(written == 0, "write file len\n");
+ ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
+ ok(written == sizeof(obuf), "write file len\n");
+ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "Peek\n");
+ ok(readden == sizeof(obuf), "peek got %d bytes\n", readden);
+ ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg);
+ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "Peek\n");
+ ok(readden == sizeof(obuf), "peek got %d bytes\n", readden);
+ todo_wine
+ ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg);
+ ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
+ todo_wine
+ ok(readden == 0, "read got %d bytes\n", readden);
+ if (readden == 0)
+ ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
+ ok(readden == sizeof(obuf), "read got %d bytes\n", readden);
+ ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check\n");
+
+ memset(ibuf, 0, sizeof(ibuf));
+ ok(WriteFile(hFile, obuf2, 0, &written, NULL), "WriteFile\n");
+ ok(written == 0, "write file len\n");
+ ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), "WriteFile\n");
+ ok(written == sizeof(obuf2), "write file len\n");
+ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "Peek\n");
+ ok(readden == sizeof(obuf2), "peek got %d bytes\n", readden);
+ ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg);
+ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "Peek\n");
+ ok(readden == sizeof(obuf2), "peek got %d bytes\n", readden);
+ todo_wine
+ ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg);
+ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
+ todo_wine
+ ok(readden == 0, "read got %d bytes\n", readden);
+ if (readden == 0)
+ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
+ ok(readden == sizeof(obuf2), "read got %d bytes\n", readden);
+ ok(memcmp(obuf2, ibuf, sizeof(obuf2)) == 0, "content check\n");
+
/* Test how ReadFile behaves when the buffer is not big enough for the whole message */
memset(ibuf, 0, sizeof(ibuf));
ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), "WriteFile 7\n");
@@ -938,6 +1205,41 @@ static void test_CloseNamedPipe(void)
hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError());
+ /* don't try to do i/o if one side couldn't be opened, as it hangs */
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n");
+ ok(written == 0, "write file len 1\n");
+
+ /* close server end without disconnecting */
+ ok(CloseHandle(hnp), "CloseHandle() failed: %08x\n", GetLastError());
+
+ todo_wine
+ ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError());
+ ok(readden == 0, "got %d bytes\n", readden);
+ /* pipe is empty now */
+
+ SetLastError(0xdeadbeef);
+ ok(!ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n");
+ todo_wine
+ ok(GetLastError() == ERROR_BROKEN_PIPE, "GetLastError() returned %08x, expected ERROR_BROKEN_PIPE\n", GetLastError());
+ SetLastError(0);
+
+ CloseHandle(hFile);
+ }
+
+ hnp = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX,
+ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+ /* nMaxInstances */ 1,
+ /* nOutBufSize */ 1024,
+ /* nInBufSize */ 1024,
+ /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+ /* lpSecurityAttrib */ NULL);
+ ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
+
+ hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
+ ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError());
+
if (hFile != INVALID_HANDLE_VALUE)
{
/* Make sure we can read and write a few bytes in both directions */
@@ -966,6 +1268,40 @@ static void test_CloseNamedPipe(void)
CloseHandle(hnp);
}
+
+ hnp = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX,
+ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+ /* nMaxInstances */ 1,
+ /* nOutBufSize */ 1024,
+ /* nInBufSize */ 1024,
+ /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+ /* lpSecurityAttrib */ NULL);
+ ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
+
+ hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
+ ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError());
+
+ /* don't try to do i/o if one side couldn't be opened, as it hangs */
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n");
+ ok(written == 0, "write file len 1\n");
+
+ /* close server end without disconnecting */
+ ok(CloseHandle(hFile), "CloseHandle() failed: %08x\n", GetLastError());
+
+ todo_wine
+ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError());
+ ok(readden == 0, "got %d bytes\n", readden);
+ /* pipe is empty now */
+
+ SetLastError(0xdeadbeef);
+ ok(!ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n");
+ ok(GetLastError() == ERROR_BROKEN_PIPE, "GetLastError() returned %08x, expected ERROR_BROKEN_PIPE\n", GetLastError());
+ SetLastError(0);
+
+ CloseHandle(hnp);
+ }
}
/** implementation of alarm() */
--
2.1.3

View File

@ -0,0 +1,52 @@
From fb6d82077a362f002300cd171547c292cbb5d0bd Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sun, 17 Aug 2014 01:29:06 +0200
Subject: ntdll: Add support for nonblocking pipes.
---
dlls/ntdll/file.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index d3f0c0e..ba3814e 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -472,6 +472,10 @@ static NTSTATUS read_unix_fd(int fd, char *buf, ULONG *total, ULONG length,
{
if (pipe_flags & NAMED_PIPE_MESSAGE_STREAM_WRITE)
{
+ int recvmsg_flags = MSG_PEEK;
+ if (*total || (pipe_flags & NAMED_PIPE_NONBLOCKING_MODE))
+ recvmsg_flags |= MSG_DONTWAIT;
+
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
@@ -483,7 +487,7 @@ static NTSTATUS read_unix_fd(int fd, char *buf, ULONG *total, ULONG length,
iov.iov_base = buf + *total;
iov.iov_len = length - *total;
- result = recvmsg( fd, &msg, MSG_PEEK | (*total ? MSG_DONTWAIT : 0) );
+ result = recvmsg( fd, &msg, recvmsg_flags );
if (result >= 0 && !(msg.msg_flags & MSG_TRUNC))
{
int ret;
@@ -527,7 +531,14 @@ static NTSTATUS read_unix_fd(int fd, char *buf, ULONG *total, ULONG length,
return STATUS_PENDING;
}
else if (errno == EAGAIN)
- return (avail_mode && *total) ? STATUS_SUCCESS : STATUS_PENDING;
+ {
+ if (avail_mode && *total)
+ return STATUS_SUCCESS;
+ else if (pipe_flags & NAMED_PIPE_NONBLOCKING_MODE)
+ return *total ? STATUS_SUCCESS : STATUS_PIPE_EMPTY;
+ else
+ return STATUS_PENDING;
+ }
else if (errno != EINTR)
return FILE_GetNtStatus();
}
--
2.1.3

View File

@ -0,0 +1,126 @@
From bd5a5c11c29a52bd7891e8c3da6ff77846085ecd Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Mon, 11 Aug 2014 04:19:49 +0200
Subject: kernel32/tests: Add tests for PIPE_NOWAIT in message mode.
---
dlls/kernel32/tests/pipe.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 96 insertions(+)
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c
index 89a13f5..49a1017 100644
--- a/dlls/kernel32/tests/pipe.c
+++ b/dlls/kernel32/tests/pipe.c
@@ -2527,6 +2527,101 @@ static void test_overlapped(void)
CloseHandle(thread);
}
+static void test_nowait(void)
+{
+ HANDLE hnp;
+ HANDLE hFile;
+ static const char obuf[] = "Bit Bucket";
+ char ibuf[32];
+ DWORD written;
+ DWORD readden;
+ DWORD lpmode;
+
+ hnp = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX,
+ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_NOWAIT,
+ /* nMaxInstances */ 1,
+ /* nOutBufSize */ 1024,
+ /* nInBufSize */ 1024,
+ /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+ /* lpSecurityAttrib */ NULL);
+ ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
+
+ hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
+ ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError());
+
+ /* don't try to do i/o if one side couldn't be opened, as it hangs */
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ /* send message from client to server */
+ ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
+ ok(written == sizeof(obuf), "write file len\n");
+ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, NULL), "Peek\n");
+ ok(readden == sizeof(obuf), "got %d bytes\n", readden);
+
+ memset(ibuf, 0, sizeof(ibuf));
+ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError());
+ ok(readden == sizeof(obuf), "got %d bytes\n", readden);
+ ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check\n");
+
+ readden = 0xdeadbeef;
+ SetLastError(0xdeadbeef);
+ ok(!ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n");
+ ok(readden == 0, "got %d bytes\n", readden);
+ ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError());
+
+ lpmode = PIPE_READMODE_MESSAGE | PIPE_NOWAIT;
+ ok(SetNamedPipeHandleState(hFile, &lpmode, NULL, NULL), "Change mode\n");
+
+ /* send message from server to client */
+ ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
+ ok(written == sizeof(obuf), "write file len\n");
+ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL), "Peek\n");
+ ok(readden == sizeof(obuf), "got %d bytes\n", readden);
+
+ memset(ibuf, 0, sizeof(ibuf));
+ ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError());
+ ok(readden == sizeof(obuf), "got %d bytes\n", readden);
+ ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check\n");
+
+ readden = 0xdeadbeef;
+ SetLastError(0xdeadbeef);
+ ok(!ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n");
+ ok(readden == 0, "got %d bytes\n", readden);
+ ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError());
+
+ /* now again the bad zero byte message test */
+ ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n");
+ ok(written == 0, "write file len\n");
+
+ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError());
+ ok(readden == 0, "got %d bytes\n", readden);
+
+ readden = 0xdeadbeef;
+ SetLastError(0xdeadbeef);
+ ok(!ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n");
+ ok(readden == 0, "got %d bytes\n", readden);
+ ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError());
+
+ /* and the same for the reverse direction */
+ ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n");
+ ok(written == 0, "write file len\n");
+
+ ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError());
+ ok(readden == 0, "got %d bytes\n", readden);
+
+ readden = 0xdeadbeef;
+ SetLastError(0xdeadbeef);
+ ok(!ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n");
+ ok(readden == 0, "got %d bytes\n", readden);
+ ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError());
+
+ ok(CloseHandle(hFile), "CloseHandle\n");
+ }
+
+ ok(CloseHandle(hnp), "CloseHandle\n");
+
+}
+
static void test_NamedPipeHandleState(void)
{
HANDLE server, client;
@@ -2952,6 +3047,7 @@ START_TEST(pipe)
test_CreatePipe();
test_impersonation();
test_overlapped();
+ test_nowait();
test_NamedPipeHandleState();
test_readfileex_pending();
}
--
2.1.3

View File

@ -0,0 +1,112 @@
From f0904b45622aa329e02dba205bfedd78379cde98 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Mon, 11 Aug 2014 05:34:19 +0200
Subject: ntdll: Allow to set PIPE_NOWAIT on byte-mode pipes.
This patch implements the functionality to set PIPE_NOWAIT on regular bytemode
pipes. This patch also extends the test to show that the implemented behaviour
matches the native implementation.
---
dlls/kernel32/tests/pipe.c | 37 +++++++++++++++++++++++++++++--------
dlls/ntdll/file.c | 2 ++
2 files changed, 31 insertions(+), 8 deletions(-)
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c
index 49a1017..f90401a 100644
--- a/dlls/kernel32/tests/pipe.c
+++ b/dlls/kernel32/tests/pipe.c
@@ -2527,7 +2527,7 @@ static void test_overlapped(void)
CloseHandle(thread);
}
-static void test_nowait(void)
+static void test_nowait(int pipemode)
{
HANDLE hnp;
HANDLE hFile;
@@ -2538,7 +2538,7 @@ static void test_nowait(void)
DWORD lpmode;
hnp = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX,
- PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_NOWAIT,
+ pipemode | PIPE_NOWAIT,
/* nMaxInstances */ 1,
/* nOutBufSize */ 1024,
/* nInBufSize */ 1024,
@@ -2569,7 +2569,7 @@ static void test_nowait(void)
ok(readden == 0, "got %d bytes\n", readden);
ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError());
- lpmode = PIPE_READMODE_MESSAGE | PIPE_NOWAIT;
+ lpmode = (pipemode & PIPE_READMODE_MESSAGE) | PIPE_NOWAIT;
ok(SetNamedPipeHandleState(hFile, &lpmode, NULL, NULL), "Change mode\n");
/* send message from server to client */
@@ -2593,8 +2593,18 @@ static void test_nowait(void)
ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n");
ok(written == 0, "write file len\n");
- ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError());
- ok(readden == 0, "got %d bytes\n", readden);
+ if (pipemode != PIPE_TYPE_BYTE)
+ {
+ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError());
+ ok(readden == 0, "got %d bytes\n", readden);
+ }
+ else
+ {
+ SetLastError(0xdeadbeef);
+ ok(!ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n");
+ ok(readden == 0, "got %d bytes\n", readden);
+ ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError());
+ }
readden = 0xdeadbeef;
SetLastError(0xdeadbeef);
@@ -2606,8 +2616,18 @@ static void test_nowait(void)
ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n");
ok(written == 0, "write file len\n");
- ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError());
- ok(readden == 0, "got %d bytes\n", readden);
+ if (pipemode != PIPE_TYPE_BYTE)
+ {
+ ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError());
+ ok(readden == 0, "got %d bytes\n", readden);
+ }
+ else
+ {
+ SetLastError(0xdeadbeef);
+ ok(!ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n");
+ ok(readden == 0, "got %d bytes\n", readden);
+ ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError());
+ }
readden = 0xdeadbeef;
SetLastError(0xdeadbeef);
@@ -3047,7 +3067,8 @@ START_TEST(pipe)
test_CreatePipe();
test_impersonation();
test_overlapped();
- test_nowait();
+ test_nowait(PIPE_TYPE_BYTE);
+ test_nowait(PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE);
test_NamedPipeHandleState();
test_readfileex_pending();
}
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index ba3814e..e564bdd 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -495,6 +495,8 @@ static NTSTATUS read_unix_fd(int fd, char *buf, ULONG *total, ULONG length,
if (ret < 0) ERR("dequeue message failed reason: %s\n", strerror(errno));
}
}
+ else if (pipe_flags & NAMED_PIPE_NONBLOCKING_MODE)
+ result = recv( fd, buf + *total, length - *total, MSG_DONTWAIT );
else
result = read( fd, buf + *total, length - *total );
--
2.1.3

View File

@ -0,0 +1,333 @@
From c0f999092e3f10053fb710d7f2ab134f9fdea592 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sun, 17 Aug 2014 02:56:57 +0200
Subject: kernel32/tests: Add additional tests for PIPE_NOWAIT in overlapped
mode.
---
dlls/kernel32/tests/pipe.c | 295 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 294 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c
index f90401a..2107294 100644
--- a/dlls/kernel32/tests/pipe.c
+++ b/dlls/kernel32/tests/pipe.c
@@ -2747,7 +2747,7 @@ static void test_readfileex_pending(void)
{
HANDLE server, client, event;
BOOL ret;
- DWORD err, wait, num_bytes;
+ DWORD err, wait, num_bytes, lpmode;
OVERLAPPED overlapped;
char read_buf[1024];
char write_buf[1024];
@@ -2905,6 +2905,160 @@ todo_wine
CloseHandle(client);
CloseHandle(server);
+ /* On Windows versions > 2000 it is not possible to add PIPE_NOWAIT to a byte-mode
+ * PIPE after creating. Create a new pipe for the following tests. */
+ server = CreateNamedPipeA(PIPENAME, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX,
+ /* dwOpenMode */ PIPE_TYPE_BYTE | PIPE_NOWAIT,
+ /* nMaxInstances */ 1,
+ /* nOutBufSize */ 1024,
+ /* nInBufSize */ 1024,
+ /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+ /* lpSecurityAttrib */ NULL);
+ ok(server != INVALID_HANDLE_VALUE, "cf failed\n");
+
+ client = CreateFileA(PIPENAME, GENERIC_READ|GENERIC_WRITE, 0, NULL,
+ OPEN_EXISTING, 0, NULL);
+ ok(client != INVALID_HANDLE_VALUE, "cf failed\n");
+
+ memset(&overlapped, 0, sizeof(overlapped));
+ overlapped.hEvent = event;
+
+ /* Initial check with empty pipe */
+ memset(read_buf, 0, sizeof(read_buf));
+ completion_called = 0;
+ ResetEvent(event);
+ ret = ReadFileEx(server, read_buf, 4, &overlapped, completion_routine);
+ ok(ret == FALSE, "ReadFileEx succeded\n");
+ ok(completion_called == 0, "completion routine called before ReadFileEx returned\n");
+ ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %d\n", GetLastError());
+ wait = WaitForSingleObjectEx(event, 0, TRUE);
+ todo_wine
+ ok(wait == WAIT_TIMEOUT, "WaitForSingleObjectEx returned %x\n", wait);
+ ok(completion_called == 0, "completion routine called before writing to file\n");
+
+ /* Call ReadFileEx after writing content to the pipe */
+ num_bytes = 0xdeadbeef;
+ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
+ ok(ret, "WriteFile failed, err=%i\n", GetLastError());
+ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+
+ memset(read_buf, 0, sizeof(read_buf));
+ completion_called = 0;
+ ResetEvent(event);
+ ret = ReadFileEx(server, read_buf, 4, &overlapped, completion_routine);
+ ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError());
+ ok(completion_called == 0, "completion routine called before ReadFileEx returned\n");
+ wait = WaitForSingleObjectEx(event, 0, TRUE);
+ ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait);
+ ok(completion_called == 1, "completion not called after writing pipe\n");
+ ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode);
+ ok(completion_num_bytes == 4, "ReadFileEx returned only %d bytes\n", completion_num_bytes);
+ ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n");
+
+ ret = ReadFile(server, read_buf + 4, sizeof(read_buf) - 4, &num_bytes, NULL);
+ ok(ret == TRUE, "ReadFile succeeded\n");
+ ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes);
+ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+
+ /* Same again, but read as a single part */
+ num_bytes = 0xdeadbeef;
+ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
+ ok(ret, "WriteFile failed, err=%i\n", GetLastError());
+ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+
+ memset(read_buf, 0, sizeof(read_buf));
+ completion_called = 0;
+ ResetEvent(event);
+ ret = ReadFileEx(server, read_buf, sizeof(read_buf), &overlapped, completion_routine);
+ ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError());
+ ok(completion_called == 0, "completion routine called before ReadFileEx returned\n");
+ wait = WaitForSingleObjectEx(event, 0, TRUE);
+ ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait);
+ ok(completion_called == 1, "completion not called after writing pipe\n");
+ ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode);
+ ok(completion_num_bytes == strlen(long_test_string), "ReadFileEx returned only %d bytes\n", completion_num_bytes);
+ ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n");
+ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+
+ /* Check content of overlapped structure */
+ memset(read_buf, 0, sizeof(read_buf));
+ S(U(overlapped)).Offset = 0;
+ S(U(overlapped)).OffsetHigh = 0;
+ overlapped.Internal = -1;
+ overlapped.InternalHigh = -1;
+ overlapped.hEvent = event;
+ num_bytes = 0xdeadbeef;
+ SetLastError(0xdeadbeef);
+ ret = ReadFile(server, read_buf, 4, &num_bytes, &overlapped);
+ ok(ret == FALSE, "ReadFile succeeded\n");
+ ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %d\n", GetLastError());
+ ok(num_bytes == 0, "bytes %u\n", num_bytes);
+ ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal);
+ todo_wine
+ ok(overlapped.InternalHigh == -1, "expected -1, got %lu\n", overlapped.InternalHigh);
+ wait = WaitForSingleObject(event, 100);
+ ok(wait == WAIT_TIMEOUT, "WaitForSingleObjectEx returned %x\n", wait);
+ ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal);
+ todo_wine
+ ok(overlapped.InternalHigh == -1, "expected -1, got %lu\n", overlapped.InternalHigh);
+
+ /* Call ReadFile after writing to the pipe */
+ num_bytes = 0xdeadbeef;
+ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
+ ok(ret, "WriteFile failed, err=%i\n", GetLastError());
+ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+
+ memset(read_buf, 0, sizeof(read_buf));
+ S(U(overlapped)).Offset = 0;
+ S(U(overlapped)).OffsetHigh = 0;
+ overlapped.Internal = -1;
+ overlapped.InternalHigh = -1;
+ overlapped.hEvent = event;
+ num_bytes = 0xdeadbeef;
+ SetLastError(0xdeadbeef);
+ ret = ReadFile(server, read_buf, 4, &num_bytes, &overlapped);
+ ok(ret == TRUE, "ReadFile failed, err=%i\n", GetLastError());
+ ok(num_bytes == 4, "bytes %u\n", num_bytes);
+ ok((NTSTATUS)overlapped.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", overlapped.Internal);
+ ok(overlapped.InternalHigh == 4, "expected 4, got %lu\n", overlapped.InternalHigh);
+ wait = WaitForSingleObject(event, 100);
+ ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait);
+ ok((NTSTATUS)overlapped.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", overlapped.Internal);
+ ok(overlapped.InternalHigh == 4, "expected 4, got %lu\n", overlapped.InternalHigh);
+
+ ret = ReadFile(server, read_buf + 4, sizeof(read_buf) - 4, &num_bytes, NULL);
+ ok(ret == TRUE, "ReadFile failed\n");
+ ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes);
+ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+
+ /* Same again, but read as a single part */
+ num_bytes = 0xdeadbeef;
+ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
+ ok(ret, "WriteFile failed, err=%i\n", GetLastError());
+ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+
+ memset(read_buf, 0, sizeof(read_buf));
+ S(U(overlapped)).Offset = 0;
+ S(U(overlapped)).OffsetHigh = 0;
+ overlapped.Internal = -1;
+ overlapped.InternalHigh = -1;
+ overlapped.hEvent = event;
+ num_bytes = 0xdeadbeef;
+ SetLastError(0xdeadbeef);
+ ret = ReadFile(server, read_buf, sizeof(read_buf), &num_bytes, &overlapped);
+ ok(ret == TRUE, "ReadFile failed, err=%i\n", GetLastError());
+ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+ ok((NTSTATUS)overlapped.Internal == 0, "expected 0, got %#lx\n", overlapped.Internal);
+ ok(overlapped.InternalHigh == strlen(long_test_string), "expected %d, got %lu\n", strlen(long_test_string), overlapped.InternalHigh);
+ wait = WaitForSingleObject(event, 100);
+ ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait);
+ ok((NTSTATUS)overlapped.Internal == 0, "expected 0, got %#lx\n", overlapped.Internal);
+ ok(overlapped.InternalHigh == strlen(long_test_string), "expected %d, got %lu\n", strlen(long_test_string), overlapped.InternalHigh);
+ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+
+ CloseHandle(client);
+ CloseHandle(server);
+
server = CreateNamedPipeA(PIPENAME, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX,
/* dwOpenMode */ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
/* nMaxInstances */ 1,
@@ -3043,6 +3197,145 @@ todo_wine
ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes);
ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+ /* Tests for PIPE_NOWAIT in message mode */
+ lpmode = PIPE_READMODE_MESSAGE | PIPE_NOWAIT;
+ ok(SetNamedPipeHandleState(server, &lpmode, NULL, NULL), "Change mode\n");
+
+ /* Initial check with empty pipe */
+ memset(read_buf, 0, sizeof(read_buf));
+ completion_called = 0;
+ ResetEvent(event);
+ ret = ReadFileEx(server, read_buf, 4, &overlapped, completion_routine);
+ ok(ret == FALSE, "ReadFileEx succeded\n");
+ ok(completion_called == 0, "completion routine called before ReadFileEx returned\n");
+ ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %d\n", GetLastError());
+ wait = WaitForSingleObjectEx(event, 0, TRUE);
+ todo_wine
+ ok(wait == WAIT_TIMEOUT, "WaitForSingleObjectEx returned %x\n", wait);
+ ok(completion_called == 0, "completion routine called before writing to file\n");
+
+ /* Call ReadFileEx after writing content to the pipe */
+ num_bytes = 0xdeadbeef;
+ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
+ ok(ret, "WriteFile failed, err=%i\n", GetLastError());
+ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+
+ memset(read_buf, 0, sizeof(read_buf));
+ completion_called = 0;
+ ResetEvent(event);
+ ret = ReadFileEx(server, read_buf, 4, &overlapped, completion_routine);
+ ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError());
+ ok(completion_called == 0, "completion routine called before ReadFileEx returned\n");
+ wait = WaitForSingleObjectEx(event, 0, TRUE);
+ ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait);
+ ok(completion_called == 1, "completion not called after writing pipe\n");
+ ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode);
+ ok(completion_num_bytes == 4, "ReadFileEx returned only %d bytes\n", completion_num_bytes);
+ ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n");
+
+ ret = ReadFile(server, read_buf + 4, sizeof(read_buf) - 4, &num_bytes, NULL);
+ ok(ret == TRUE, "ReadFile succeeded\n");
+ ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes);
+ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+
+ /* Same again, but read as a single part */
+ num_bytes = 0xdeadbeef;
+ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
+ ok(ret, "WriteFile failed, err=%i\n", GetLastError());
+ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+
+ memset(read_buf, 0, sizeof(read_buf));
+ completion_called = 0;
+ ResetEvent(event);
+ ret = ReadFileEx(server, read_buf, sizeof(read_buf), &overlapped, completion_routine);
+ ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError());
+ ok(completion_called == 0, "completion routine called before ReadFileEx returned\n");
+ wait = WaitForSingleObjectEx(event, 0, TRUE);
+ ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait);
+ ok(completion_called == 1, "completion not called after writing pipe\n");
+ ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode);
+ ok(completion_num_bytes == strlen(long_test_string), "ReadFileEx returned only %d bytes\n", completion_num_bytes);
+ ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n");
+ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+
+ /* Check content of overlapped structure */
+ memset(read_buf, 0, sizeof(read_buf));
+ S(U(overlapped)).Offset = 0;
+ S(U(overlapped)).OffsetHigh = 0;
+ overlapped.Internal = -1;
+ overlapped.InternalHigh = -1;
+ overlapped.hEvent = event;
+ num_bytes = 0xdeadbeef;
+ SetLastError(0xdeadbeef);
+ ret = ReadFile(server, read_buf, 4, &num_bytes, &overlapped);
+ ok(ret == FALSE, "ReadFile succeeded\n");
+ ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %d\n", GetLastError());
+ ok(num_bytes == 0, "bytes %u\n", num_bytes);
+ ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal);
+ todo_wine
+ ok(overlapped.InternalHigh == -1, "expected -1, got %lu\n", overlapped.InternalHigh);
+ wait = WaitForSingleObject(event, 100);
+ ok(wait == WAIT_TIMEOUT, "WaitForSingleObjectEx returned %x\n", wait);
+ ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal);
+ todo_wine
+ ok(overlapped.InternalHigh == -1, "expected -1, got %lu\n", overlapped.InternalHigh);
+
+ /* Call ReadFile after writing to the pipe */
+ num_bytes = 0xdeadbeef;
+ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
+ ok(ret, "WriteFile failed, err=%i\n", GetLastError());
+ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+
+ memset(read_buf, 0, sizeof(read_buf));
+ S(U(overlapped)).Offset = 0;
+ S(U(overlapped)).OffsetHigh = 0;
+ overlapped.Internal = -1;
+ overlapped.InternalHigh = -1;
+ overlapped.hEvent = event;
+ num_bytes = 0xdeadbeef;
+ SetLastError(0xdeadbeef);
+ ret = ReadFile(server, read_buf, 4, &num_bytes, &overlapped);
+ ok(ret == FALSE, "ReadFile succeeded\n");
+ ok(GetLastError() == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", GetLastError());
+ todo_wine
+ ok(num_bytes == 0, "bytes %u\n", num_bytes);
+ ok((NTSTATUS)overlapped.Internal == STATUS_BUFFER_OVERFLOW, "expected STATUS_BUFFER_OVERFLOW, got %#lx\n", overlapped.Internal);
+ ok(overlapped.InternalHigh == 4, "expected 4, got %lu\n", overlapped.InternalHigh);
+ wait = WaitForSingleObject(event, 100);
+ ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait);
+ ok((NTSTATUS)overlapped.Internal == STATUS_BUFFER_OVERFLOW, "expected STATUS_BUFFER_OVERFLOW, got %#lx\n", overlapped.Internal);
+ ok(overlapped.InternalHigh == 4, "expected 4, got %lu\n", overlapped.InternalHigh);
+
+ ret = ReadFile(server, read_buf + 4, sizeof(read_buf) - 4, &num_bytes, NULL);
+ ok(ret == TRUE, "ReadFile failed\n");
+ ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes);
+ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+
+ /* Same again, but read as a single part */
+ num_bytes = 0xdeadbeef;
+ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
+ ok(ret, "WriteFile failed, err=%i\n", GetLastError());
+ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+
+ memset(read_buf, 0, sizeof(read_buf));
+ S(U(overlapped)).Offset = 0;
+ S(U(overlapped)).OffsetHigh = 0;
+ overlapped.Internal = -1;
+ overlapped.InternalHigh = -1;
+ overlapped.hEvent = event;
+ num_bytes = 0xdeadbeef;
+ SetLastError(0xdeadbeef);
+ ret = ReadFile(server, read_buf, sizeof(read_buf), &num_bytes, &overlapped);
+ ok(ret == TRUE, "ReadFile failed, err=%i\n", GetLastError());
+ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+ ok((NTSTATUS)overlapped.Internal == 0, "expected 0, got %#lx\n", overlapped.Internal);
+ ok(overlapped.InternalHigh == strlen(long_test_string), "expected %d, got %lu\n", strlen(long_test_string), overlapped.InternalHigh);
+ wait = WaitForSingleObject(event, 100);
+ ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait);
+ ok((NTSTATUS)overlapped.Internal == 0, "expected 0, got %#lx\n", overlapped.Internal);
+ ok(overlapped.InternalHigh == strlen(long_test_string), "expected %d, got %lu\n", strlen(long_test_string), overlapped.InternalHigh);
+ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+
CloseHandle(client);
CloseHandle(server);
CloseHandle(event);
--
2.1.3

View File

@ -1 +1,2 @@
Fixes: [16550] Fix for ConnectNamedPort return value in overlapped mode
Fixes: [17195] Support for named pipe message mode

View File

@ -1,22 +1,22 @@
From 8acfd293ecd49b7cad340dc90e6ea6b0ed07289a Mon Sep 17 00:00:00 2001
From 9986fca2fe9cc57f9c7a01f08fc6a826a398de47 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 16 Jan 2014 19:08:30 -0700
Subject: ws2_32: Add support for TF_DISCONNECT and TF_REUSE_SOCKET to
TransmitFile.
---
dlls/ws2_32/socket.c | 17 ++++++++++--
dlls/ws2_32/tests/sock.c | 11 +++++++-
include/winsock.h | 1 +
server/protocol.def | 6 +++++
server/sock.c | 66 +++++++++++++++++++++++++++++++++++++++-------
5 files changed, 89 insertions(+), 12 deletions(-)
dlls/ws2_32/socket.c | 17 +++++++++++--
dlls/ws2_32/tests/sock.c | 11 +++++++-
include/winsock.h | 1 +
server/protocol.def | 6 +++++
server/sock.c | 65 +++++++++++++++++++++++++++++++++++++++++-------
5 files changed, 88 insertions(+), 12 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 42c7832..ddb50a5 100644
index dbcadb3..e74aa7c 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -2558,6 +2558,18 @@ static BOOL WS2_transmitfile_base( SOCKET s, HANDLE h, DWORD total_bytes, DWORD
@@ -2560,6 +2560,18 @@ static BOOL WS2_transmitfile_base( SOCKET s, HANDLE h, DWORD total_bytes, DWORD
if (buffers && WS_send( s, buffers->Tail, buffers->TailLength, 0 ) == SOCKET_ERROR)
goto cleanup;
@ -35,7 +35,7 @@ index 42c7832..ddb50a5 100644
ret = TRUE;
cleanup:
@@ -2599,6 +2611,7 @@ static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD total_bytes, DWOR
@@ -2601,6 +2613,7 @@ static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD total_bytes, DWOR
{
union generic_unix_sockaddr uaddr;
unsigned int uaddrlen = sizeof(uaddr);
@ -43,7 +43,7 @@ index 42c7832..ddb50a5 100644
IO_STATUS_BLOCK *iosb = (IO_STATUS_BLOCK *)overlapped;
struct ws2_transmitfile_async *wsa;
int status, fd;
@@ -2619,8 +2632,8 @@ static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD total_bytes, DWOR
@@ -2621,8 +2634,8 @@ static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD total_bytes, DWOR
return FALSE;
}
release_sock_fd( s, fd );
@ -55,10 +55,10 @@ index 42c7832..ddb50a5 100644
if (!overlapped)
return WS2_transmitfile_base( s, h, total_bytes, bytes_per_send, overlapped, buffers, flags );
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index dbb762a..5bf23a0 100644
index 9708cf1..cf9ba23 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -6684,8 +6684,17 @@ static void test_TransmitFile(void)
@@ -7008,8 +7008,17 @@ static void test_TransmitFile(void)
ok(iret == WAIT_OBJECT_0, "Overlapped TransmitFile failed.\n");
compare_file(file, dest, 10);
@ -78,10 +78,10 @@ index dbb762a..5bf23a0 100644
bret = pTransmitFile(client, NULL, 0, 0, NULL, NULL, 0);
err = WSAGetLastError();
diff --git a/include/winsock.h b/include/winsock.h
index 06e6309..4426557 100644
index 50237e8..e53aa1e 100644
--- a/include/winsock.h
+++ b/include/winsock.h
@@ -810,6 +810,7 @@ typedef struct WS(WSAData)
@@ -814,6 +814,7 @@ typedef struct WS(WSAData)
/* internal per-socket flags */
#ifdef __WINESRC__
@ -90,7 +90,7 @@ index 06e6309..4426557 100644
#define FD_WINE_NONBLOCKING 0x20000000
#define FD_WINE_CONNECTED 0x40000000
diff --git a/server/protocol.def b/server/protocol.def
index c9270ea..328f8a8 100644
index fc6bec5..64e3f18 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1208,6 +1208,12 @@ enum server_fd_type
@ -107,7 +107,7 @@ index c9270ea..328f8a8 100644
@REQ(set_socket_event)
obj_handle_t handle; /* handle to the socket */
diff --git a/server/sock.c b/server/sock.c
index 4adad0f..15afe81 100644
index 7c0212e..4d51950 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -80,6 +80,7 @@
@ -118,16 +118,15 @@ index 4adad0f..15afe81 100644
#define FD_WINE_LISTENING 0x10000000
#define FD_WINE_NONBLOCKING 0x20000000
#define FD_WINE_CONNECTED 0x40000000
@@ -124,6 +125,8 @@ static void sock_queue_async( struct fd *fd, const async_data_t *data, int type,
@@ -124,6 +125,7 @@ static enum server_fd_type sock_get_fd_type( struct fd *fd );
static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count );
static void sock_reselect_async( struct fd *fd, struct async_queue *queue );
static void sock_cancel_async( struct fd *fd, struct process *process, struct thread *thread, client_ptr_t iosb );
+static int sock_close_handle( struct object *obj, struct process *process, obj_handle_t handle );
+
static int sock_get_ntstatus( int err );
static int sock_get_error( int err );
static void sock_set_error(void);
@@ -144,7 +147,7 @@ static const struct object_ops sock_ops =
@@ -145,7 +147,7 @@ static const struct object_ops sock_ops =
default_set_sd, /* set_sd */
no_lookup_name, /* lookup_name */
no_open_file, /* open_file */
@ -136,7 +135,7 @@ index 4adad0f..15afe81 100644
sock_destroy /* destroy */
};
@@ -583,6 +586,47 @@ static struct fd *sock_get_fd( struct object *obj )
@@ -585,6 +587,47 @@ static struct fd *sock_get_fd( struct object *obj )
return (struct fd *)grab_object( sock->fd );
}
@ -184,7 +183,7 @@ index 4adad0f..15afe81 100644
static void sock_destroy( struct object *obj )
{
struct sock *sock = (struct sock *)obj;
@@ -630,15 +674,8 @@ static struct object *create_socket( int family, int type, int protocol, unsigne
@@ -633,15 +676,8 @@ static struct object *create_socket( int family, int type, int protocol, unsigne
struct sock *sock;
int sockfd;
@ -201,7 +200,7 @@ index 4adad0f..15afe81 100644
if (!(sock = alloc_object( &sock_ops )))
{
close( sockfd );
@@ -963,6 +1000,17 @@ DECL_HANDLER(accept_into_socket)
@@ -969,6 +1005,17 @@ DECL_HANDLER(accept_into_socket)
release_object( sock );
}
@ -220,5 +219,5 @@ index 4adad0f..15afe81 100644
DECL_HANDLER(set_socket_event)
{
--
1.7.9.5
2.1.3