diff options
Diffstat (limited to 'pkg/tcpip')
-rw-r--r-- | pkg/tcpip/tcpip.go | 9 | ||||
-rw-r--r-- | pkg/tcpip/tcpip_state_autogen.go | 27 | ||||
-rw-r--r-- | pkg/tcpip/transport/tcp/endpoint.go | 33 | ||||
-rw-r--r-- | pkg/tcpip/transport/tcp/tcp_state_autogen.go | 3 |
4 files changed, 72 insertions, 0 deletions
diff --git a/pkg/tcpip/tcpip.go b/pkg/tcpip/tcpip.go index 07c85ce59..290c4e138 100644 --- a/pkg/tcpip/tcpip.go +++ b/pkg/tcpip/tcpip.go @@ -978,6 +978,15 @@ const ( TCPTimeWaitReuseLoopbackOnly ) +// LingerOption is used by SetSockOpt/GetSockOpt to set/get the +// duration for which a socket lingers before returning from Close. +// +// +stateify savable +type LingerOption struct { + Enabled bool + Timeout time.Duration +} + // IPPacketInfo is the message structure for IP_PKTINFO. // // +stateify savable diff --git a/pkg/tcpip/tcpip_state_autogen.go b/pkg/tcpip/tcpip_state_autogen.go index 827b27692..034b39c1f 100644 --- a/pkg/tcpip/tcpip_state_autogen.go +++ b/pkg/tcpip/tcpip_state_autogen.go @@ -111,6 +111,32 @@ func (x *LinkPacketInfo) StateLoad(m state.Source) { m.Load(1, &x.PktType) } +func (x *LingerOption) StateTypeName() string { + return "pkg/tcpip.LingerOption" +} + +func (x *LingerOption) StateFields() []string { + return []string{ + "Enabled", + "Timeout", + } +} + +func (x *LingerOption) beforeSave() {} + +func (x *LingerOption) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.Enabled) + m.Save(1, &x.Timeout) +} + +func (x *LingerOption) afterLoad() {} + +func (x *LingerOption) StateLoad(m state.Source) { + m.Load(0, &x.Enabled) + m.Load(1, &x.Timeout) +} + func (x *IPPacketInfo) StateTypeName() string { return "pkg/tcpip.IPPacketInfo" } @@ -144,5 +170,6 @@ func init() { state.Register((*FullAddress)(nil)) state.Register((*ControlMessages)(nil)) state.Register((*LinkPacketInfo)(nil)) + state.Register((*LingerOption)(nil)) state.Register((*IPPacketInfo)(nil)) } diff --git a/pkg/tcpip/transport/tcp/endpoint.go b/pkg/tcpip/transport/tcp/endpoint.go index 9c0f4c9f4..ff9b8804d 100644 --- a/pkg/tcpip/transport/tcp/endpoint.go +++ b/pkg/tcpip/transport/tcp/endpoint.go @@ -654,6 +654,9 @@ type endpoint struct { // owner is used to get uid and gid of the packet. owner tcpip.PacketOwner + + // linger is used for SO_LINGER socket option. + linger tcpip.LingerOption } // UniqueID implements stack.TransportEndpoint.UniqueID. @@ -1007,6 +1010,26 @@ func (e *endpoint) Close() { return } + if e.linger.Enabled && e.linger.Timeout == 0 { + s := e.EndpointState() + isResetState := s == StateEstablished || s == StateCloseWait || s == StateFinWait1 || s == StateFinWait2 || s == StateSynRecv + if isResetState { + // Close the endpoint without doing full shutdown and + // send a RST. + e.resetConnectionLocked(tcpip.ErrConnectionAborted) + e.closeNoShutdownLocked() + + // Wake up worker to close the endpoint. + switch s { + case StateSynRecv: + e.notifyProtocolGoroutine(notifyClose) + default: + e.notifyProtocolGoroutine(notifyTickleWorker) + } + return + } + } + // Issue a shutdown so that the peer knows we won't send any more data // if we're connected, or stop accepting if we're listening. e.shutdownLocked(tcpip.ShutdownWrite | tcpip.ShutdownRead) @@ -1807,6 +1830,11 @@ func (e *endpoint) SetSockOpt(opt interface{}) *tcpip.Error { case tcpip.SocketDetachFilterOption: return nil + case tcpip.LingerOption: + e.LockUser() + e.linger = v + e.UnlockUser() + default: return nil } @@ -2032,6 +2060,11 @@ func (e *endpoint) GetSockOpt(opt interface{}) *tcpip.Error { Port: port, } + case *tcpip.LingerOption: + e.LockUser() + *o = e.linger + e.UnlockUser() + default: return tcpip.ErrUnknownProtocolOption } diff --git a/pkg/tcpip/transport/tcp/tcp_state_autogen.go b/pkg/tcpip/transport/tcp/tcp_state_autogen.go index bed45e9a1..77e0d0e97 100644 --- a/pkg/tcpip/transport/tcp/tcp_state_autogen.go +++ b/pkg/tcpip/transport/tcp/tcp_state_autogen.go @@ -222,6 +222,7 @@ func (x *endpoint) StateFields() []string { "closed", "txHash", "owner", + "linger", } } @@ -293,6 +294,7 @@ func (x *endpoint) StateSave(m state.Sink) { m.Save(59, &x.closed) m.Save(60, &x.txHash) m.Save(61, &x.owner) + m.Save(62, &x.linger) } func (x *endpoint) StateLoad(m state.Source) { @@ -354,6 +356,7 @@ func (x *endpoint) StateLoad(m state.Source) { m.Load(59, &x.closed) m.Load(60, &x.txHash) m.Load(61, &x.owner) + m.Load(62, &x.linger) m.LoadValue(3, new(string), func(y interface{}) { x.loadLastError(y.(string)) }) m.LoadValue(10, new(EndpointState), func(y interface{}) { x.loadState(y.(EndpointState)) }) m.LoadValue(25, new(unixTime), func(y interface{}) { x.loadRecentTSTime(y.(unixTime)) }) |