This error used to just be a `errors.New` with the text exactly matching
the "use of closed network connection" that you'd get from the Go stdlib.
Now that that error was exported as `net.ErrClosed` in Go 1.16 we should
be able to swap to this safely, and anyone who relied on checking the
string explicitly should still be fine.
Signed-off-by: Daniel Canter <dcanter@microsoft.com>
1.13 is sufficiently old at this point and net.ErrClosed from 1.16 will be nice
to use.
This change additionally runs go fmt to bring in the new 1.17 build tag syntax
and builds the binaries in our CI with 1.17+.
Signed-off-by: Daniel Canter <dcanter@microsoft.com>
ListenPipe can fail if there is a concurrent DialPipe because there is a
race window where DialPipe can connect to the initial server named pipe
before it is connected to and closed by ListenPipe.
To fix this, use the lower-level NT API for creating the server pipe,
since this API allows for specifying that a server pipe should initially
be in the disconnected state instead of the listening state. This allows
us to avoid the race condition by creating the pipe in the correct state
initially, so there is no longer a need to create a dummy client
connection.
This changes a few things to try to ensure that we never wind up with
a result of ERROR_FILE_NOT_FOUND, due to a race between closing the
last pipe instance and opening the next.
First we keep an "open" client instance (unused) while the listener
is open, so that we are guaranteed to always have an active pipe
instance. This means attempts to open while no other instances exist
result in ERROR_PIPE_BUSY instead of ERROR_FILE_NOT_FOUND.
Second we have changed the loop for dialing to eliminate a race condition
that is more or less inherent in WaitNamedPipe when synchronizing with
CreateFile. The real timeout needs to be some larger value than the
WaitNamedPipe timeout, and furthermore WaitNamedPipe is not very nice
with the Go runtime, since it is a blocking system call. Instead we
just put the goroutine to sleep for 10 milliseconds, and keep retrying
the CreateFile until the maximum timeout is reached. If no timeout is
specified we assume a reasonable and large default of 5 seconds, which is
similar to a TCP connection timeout.
This isn't perfect, as a client attempting to connect to an extremely
busy pipe server can be starved out by other clients coming in while
it is in that brief sleep, but this potential race was already present
with WaitNamedPipe. The numerous retries (by default 500 retries!)
mean its pretty unlikely to occur, and if a single client hits the
race once, it has an excellent chance of getting in the next cycle.
(A real "fix" that is completely race free and fair would require
changes in the underlying Named Pipe implementation, or some other
kind of external coordination.)
This change resolves the issue where Accept() returns ERROR_NO_DATA
because the client closes the connection immediately. It resolves
the race by ignoring that particular connection and waiting on a
new one.
In order to upgrade to go1.8 all IO operations
including previous pending IO must have the deadline
set when SetReadDeadline or SetWriteDeadline is called
Signed-off-by: Darren Stahl <darst@microsoft.com>
This forces any pending data to be sent to the remote party before
emitting the 0-length EOF message, to make sure it appears as a seperate
message.
This fixes the "TestEchoWithMessaging" test
Signed-off-by: Simon Ferquel <simon.ferquel@docker.com>
This change adds support for message mode pipes and uses them to support
CloseWrite() to better match TCP and UNIX sockets. Message mode pipes
support writing and (optionally) reading data in message-sized chunks.
This is useful for us because when in this mode a zero-sized message can
be read. We use this zero-sized message to signal that no more writes will
arrive. This is not standard practice in Windows, but it is a reasonable
compromise.
This ensures that the pipe server cannot impersonate or even identify
the user that has connected to the pipe. This is a good default to
prevent malicious squatting on a named pipe name.
Signed-off-by: John Starks <jostarks@microsoft.com>
This includes Reader, Writer, and Closer interfaces on top of
Windows file handles in a way that does not block the system thread
while the IO is outstanding.
This also includes net.Listener and net.Conn for named pipes.