diff options
author | Ben Burkert <ben@benburkert.com> | 2019-04-19 19:28:10 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2019-04-19 19:29:05 -0700 |
commit | 56927e5317151d5775366c6315f2054e0ae0e23a (patch) | |
tree | f0d52df2df455ef90e177155e5c962969ea2fc87 /pkg/tcpip/transport/tcp/endpoint.go | |
parent | 358eb52a76ebd41baf52972f901af0ff398e131b (diff) |
tcpip/transport/tcp: read side only shutdown of an endpoint
Support shutdown on only the read side of an endpoint. Reads performed
after a call to Shutdown with only the ShutdownRead flag will return
ErrClosedForReceive without data.
Break out the shutdown(2) with SHUT_RD syscall test into to two tests.
The first tests that no packets are sent when shutting down the read
side of a socket. The second tests that, after shutting down the read
side of a socket, unread data can still be read, or an EOF if there is
no more data to read.
Change-Id: I9d7c0a06937909cbb466b7591544a4bcaebb11ce
PiperOrigin-RevId: 244459430
Diffstat (limited to 'pkg/tcpip/transport/tcp/endpoint.go')
-rw-r--r-- | pkg/tcpip/transport/tcp/endpoint.go | 29 |
1 files changed, 16 insertions, 13 deletions
diff --git a/pkg/tcpip/transport/tcp/endpoint.go b/pkg/tcpip/transport/tcp/endpoint.go index c0b785431..09eff5be1 100644 --- a/pkg/tcpip/transport/tcp/endpoint.go +++ b/pkg/tcpip/transport/tcp/endpoint.go @@ -1199,21 +1199,24 @@ func (e *endpoint) Shutdown(flags tcpip.ShutdownFlags) *tcpip.Error { switch e.state { case stateConnected: - // Close for write. - if (e.shutdownFlags & tcpip.ShutdownWrite) != 0 { - if (e.shutdownFlags & tcpip.ShutdownRead) != 0 { - // We're fully closed, if we have unread data we need to abort - // the connection with a RST. - e.rcvListMu.Lock() - rcvBufUsed := e.rcvBufUsed - e.rcvListMu.Unlock() - - if rcvBufUsed > 0 { - e.notifyProtocolGoroutine(notifyReset) - return nil - } + // Close for read. + if (e.shutdownFlags & tcpip.ShutdownRead) != 0 { + // Mark read side as closed. + e.rcvListMu.Lock() + e.rcvClosed = true + rcvBufUsed := e.rcvBufUsed + e.rcvListMu.Unlock() + + // If we're fully closed and we have unread data we need to abort + // the connection with a RST. + if (e.shutdownFlags&tcpip.ShutdownWrite) != 0 && rcvBufUsed > 0 { + e.notifyProtocolGoroutine(notifyReset) + return nil } + } + // Close for write. + if (e.shutdownFlags & tcpip.ShutdownWrite) != 0 { e.sndBufMu.Lock() if e.sndClosed { |