summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/tcpip')
-rw-r--r--pkg/tcpip/tcpip.go9
-rw-r--r--pkg/tcpip/tcpip_state_autogen.go27
-rw-r--r--pkg/tcpip/transport/tcp/endpoint.go33
-rw-r--r--pkg/tcpip/transport/tcp/tcp_state_autogen.go3
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)) })