Differences between named pipes in Windows and Wine

Ryan Prichard ryan.prichard at gmail.com
Mon Jun 13 20:49:08 CDT 2016


Hi,

I noticed a handful of differences in the "lifecycle" of named pipes
between Windows and Wine, and I figured I'd post about them here.  I wrote
a standalone one-file C++ program that demonstrates the differences I
found.  (In that test, the pipe handles are always overlapped and
PIPE_WAIT.)  I tested using wine-1.9.12.

The differences were:

1. With Windows, there can be multiple concurrent ConnectNamedPipe
operations on a pipe.  With Wine, the second ConnectNamedPipe call fails
with ERROR_INVALID_HANDLE.

2. With Windows, DisconnectNamedPipe aborts ConnectNamedPipe operations
with the error ERROR_PIPE_NOT_CONNECTED.  The DisconnectNamedPipe call
succeeds, and the pipe is no longer listening.  With Wine, the
DisconnectNamedPipe call itself fails with ERROR_PIPE_LISTENING, and the
pipe is still listening.

3. With Windows, if the server breaks the pipe by closing its handle, the
client can finish reading the remaining data in the pipe.  Once the data is
gone, reading from a broken pipe fails with ERROR_BROKEN_PIPE.  Writing to
a broken pipe fails with ERROR_NO_DATA.  With Wine, once the server breaks
the pipe, the client cannot read the remaining data, and I/O on a broken
pipe fails with ERROR_PIPE_NOT_CONNECTED.  (Exception: ReadFile on a server
pipe still returns ERROR_BROKEN_PIPE.)

4. Calling ConnectNamedPipe on a broken server pipe fails
with ERROR_NO_DATA on Windows, but ERROR_NO_DATA_DETECTED on Wine.

My test program is at:
https://gist.github.com/rprichard/8dd8ca134b39534b7da2733994aa07ba.  It
passes on XP, Vista, Win7, and Win10, with the exception of
testChangeMaxInstancesAfterClosingLastServerHandle, which passes on Vista
and up.  A couple of the more interesting tests are testDisconnectAtStartup
and testReadFromBrokenClientPipe:

testDisconnectAtStartup:

// Calling DisconnectNamedPipe on a new pipe successfully transitions it to
a
// "Not Connected" state.  The second DisconnectNamedPipe call fails, and
the
// client can't connect.
void testDisconnectAtStartup() {
    const HANDLE server = assertValid(openServer(name(0)));
    CHECK_SUCCESS(DisconnectNamedPipe(server));
    CHECK(createFile(name(0)) == INVALID_HANDLE_VALUE);
    CHECK_FAILURE(DisconnectNamedPipe(server), ERROR_PIPE_NOT_CONNECTED);
    CHECK(createFile(name(0)) == INVALID_HANDLE_VALUE);
    CHECK_SUCCESS(CloseHandle(server));
}

// If a client pipe is broken, rather than disconnected, the remaining data
can
// still be read.
void testReadFromBrokenClientPipe() {
    DWORD actual = 0;
    Over over;
    char buf[2] = {};

    const HANDLE server = assertValid(openServer(name(0)));
    const HANDLE client = assertValid(createFile(name(0)));
    CHECK_SUCCESS(WriteFile(server, buf, 1, &actual, &over));
    CHECK_SUCCESS(CloseHandle(server));

    CHECK_SUCCESS(ReadFile(client, buf, 2, &actual, &over));
    CHECK(actual == 1);
    CHECK_FAILURE(ReadFile(client, buf, 2, &actual, &over),
ERROR_BROKEN_PIPE);

    CHECK_SUCCESS(CloseHandle(client));
}

I know that item #3 above breaks my winpty project (in principle), where a
pipe server signals EOF by closing a pipe without disconnecting it.  The
winpty client can read all the output before hitting the broken pipe.  I
suspect winpty may not run on Wine anyway, though.

-Ryan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.winehq.org/pipermail/wine-devel/attachments/20160613/9b68b41b/attachment-0001.html>


More information about the wine-devel mailing list