Move SO_LINGER option to socketops.

PiperOrigin-RevId: 347437786
This commit is contained in:
Nayana Bidari 2020-12-14 12:00:46 -08:00 committed by gVisor bot
parent 65e4ed8fbe
commit 2e191cb3f7
9 changed files with 48 additions and 131 deletions

View File

@ -428,11 +428,7 @@ func (s *socketOpsCommon) Release(ctx context.Context) {
return
}
var v tcpip.LingerOption
if err := s.Endpoint.GetSockOpt(&v); err != nil {
return
}
v := s.Endpoint.SocketOptions().GetLinger()
// The case for zero timeout is handled in tcp endpoint close function.
// Close is blocked until either:
// 1. The endpoint state is not in any of the states: FIN-WAIT1,
@ -1092,11 +1088,8 @@ func getSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, fam
return nil, syserr.ErrInvalidArgument
}
var v tcpip.LingerOption
var linger linux.Linger
if err := ep.GetSockOpt(&v); err != nil {
return nil, syserr.TranslateNetstackError(err)
}
v := ep.SocketOptions().GetLinger()
if v.Enabled {
linger.OnOff = 1
@ -1899,10 +1892,11 @@ func setSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, nam
socket.SetSockOptEmitUnimplementedEvent(t, name)
}
return syserr.TranslateNetstackError(
ep.SetSockOpt(&tcpip.LingerOption{
Enabled: v.OnOff != 0,
Timeout: time.Second * time.Duration(v.Linger)}))
ep.SocketOptions().SetLinger(tcpip.LingerOption{
Enabled: v.OnOff != 0,
Timeout: time.Second * time.Duration(v.Linger),
})
return nil
case linux.SO_DETACH_FILTER:
// optval is ignored.

View File

@ -746,9 +746,6 @@ type baseEndpoint struct {
// or may be used if the endpoint is connected.
path string
// linger is used for SO_LINGER socket option.
linger tcpip.LingerOption
// ops is used to get socket level options.
ops tcpip.SocketOptions
}
@ -840,12 +837,6 @@ func (e *baseEndpoint) SendMsg(ctx context.Context, data [][]byte, c ControlMess
// SetSockOpt sets a socket option.
func (e *baseEndpoint) SetSockOpt(opt tcpip.SettableSocketOption) *tcpip.Error {
switch v := opt.(type) {
case *tcpip.LingerOption:
e.Lock()
e.linger = *v
e.Unlock()
}
return nil
}
@ -922,17 +913,8 @@ func (e *baseEndpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, *tcpip.Error) {
// GetSockOpt implements tcpip.Endpoint.GetSockOpt.
func (e *baseEndpoint) GetSockOpt(opt tcpip.GettableSocketOption) *tcpip.Error {
switch o := opt.(type) {
case *tcpip.LingerOption:
e.Lock()
*o = e.linger
e.Unlock()
return nil
default:
log.Warningf("Unsupported socket option: %T", opt)
return tcpip.ErrUnknownProtocolOption
}
log.Warningf("Unsupported socket option: %T", opt)
return tcpip.ErrUnknownProtocolOption
}
// LastError implements Endpoint.LastError.

View File

@ -16,6 +16,8 @@ package tcpip
import (
"sync/atomic"
"gvisor.dev/gvisor/pkg/sync"
)
// SocketOptionsHandler holds methods that help define endpoint specific
@ -77,24 +79,24 @@ type SocketOptions struct {
// These fields are accessed and modified using atomic operations.
// broadcastEnabled determines whether datagram sockets are allowed to send
// packets to a broadcast address.
// broadcastEnabled determines whether datagram sockets are allowed to
// send packets to a broadcast address.
broadcastEnabled uint32
// passCredEnabled determines whether SCM_CREDENTIALS socket control messages
// are enabled.
// passCredEnabled determines whether SCM_CREDENTIALS socket control
// messages are enabled.
passCredEnabled uint32
// noChecksumEnabled determines whether UDP checksum is disabled while
// transmitting for this socket.
noChecksumEnabled uint32
// reuseAddressEnabled determines whether Bind() should allow reuse of local
// address.
// reuseAddressEnabled determines whether Bind() should allow reuse of
// local address.
reuseAddressEnabled uint32
// reusePortEnabled determines whether to permit multiple sockets to be bound
// to an identical socket address.
// reusePortEnabled determines whether to permit multiple sockets to be
// bound to an identical socket address.
reusePortEnabled uint32
// keepAliveEnabled determines whether TCP keepalive is enabled for this
@ -142,6 +144,13 @@ type SocketOptions struct {
// receiveOriginalDstAddress is used to specify if the original destination of
// the incoming packet should be returned as an ancillary message.
receiveOriginalDstAddress uint32
// mu protects the access to the below fields.
mu sync.Mutex `state:"nosave"`
// linger determines the amount of time the socket should linger before
// close. We currently implement this option for TCP socket only.
linger LingerOption
}
// InitHandler initializes the handler. This must be called before using the
@ -338,3 +347,18 @@ func (*SocketOptions) GetOutOfBandInline() bool {
// SetOutOfBandInline sets value for SO_OOBINLINE option. We currently do not
// support disabling this option.
func (*SocketOptions) SetOutOfBandInline(bool) {}
// GetLinger gets value for SO_LINGER option.
func (so *SocketOptions) GetLinger() LingerOption {
so.mu.Lock()
linger := so.linger
so.mu.Unlock()
return linger
}
// SetLinger sets value for SO_LINGER option.
func (so *SocketOptions) SetLinger(linger LingerOption) {
so.mu.Lock()
so.linger = linger
so.mu.Unlock()
}

View File

@ -1145,10 +1145,6 @@ type LingerOption struct {
Timeout time.Duration
}
func (*LingerOption) isGettableSocketOption() {}
func (*LingerOption) isSettableSocketOption() {}
// IPPacketInfo is the message structure for IP_PKTINFO.
//
// +stateify savable

View File

@ -75,8 +75,6 @@ type endpoint struct {
route *stack.Route `state:"manual"`
ttl uint8
stats tcpip.TransportEndpointStats `state:"nosave"`
// linger is used for SO_LINGER socket option.
linger tcpip.LingerOption
// owner is used to get uid and gid of the packet.
owner tcpip.PacketOwner
@ -338,15 +336,6 @@ func (e *endpoint) Peek([][]byte) (int64, *tcpip.Error) {
// SetSockOpt sets a socket option.
func (e *endpoint) SetSockOpt(opt tcpip.SettableSocketOption) *tcpip.Error {
switch v := opt.(type) {
case *tcpip.SocketDetachFilterOption:
return nil
case *tcpip.LingerOption:
e.mu.Lock()
e.linger = *v
e.mu.Unlock()
}
return nil
}
@ -399,16 +388,7 @@ func (e *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, *tcpip.Error) {
// GetSockOpt implements tcpip.Endpoint.GetSockOpt.
func (e *endpoint) GetSockOpt(opt tcpip.GettableSocketOption) *tcpip.Error {
switch o := opt.(type) {
case *tcpip.LingerOption:
e.mu.Lock()
*o = e.linger
e.mu.Unlock()
return nil
default:
return tcpip.ErrUnknownProtocolOption
}
return tcpip.ErrUnknownProtocolOption
}
func send4(r *stack.Route, ident uint16, data buffer.View, ttl uint8, owner tcpip.PacketOwner) *tcpip.Error {

View File

@ -85,8 +85,6 @@ type endpoint struct {
stats tcpip.TransportEndpointStats `state:"nosave"`
bound bool
boundNIC tcpip.NICID
// linger is used for SO_LINGER socket option.
linger tcpip.LingerOption
// lastErrorMu protects lastError.
lastErrorMu sync.Mutex `state:"nosave"`
@ -306,16 +304,10 @@ func (ep *endpoint) Readiness(mask waiter.EventMask) waiter.EventMask {
// used with SetSockOpt, and this function always returns
// tcpip.ErrNotSupported.
func (ep *endpoint) SetSockOpt(opt tcpip.SettableSocketOption) *tcpip.Error {
switch v := opt.(type) {
switch opt.(type) {
case *tcpip.SocketDetachFilterOption:
return nil
case *tcpip.LingerOption:
ep.mu.Lock()
ep.linger = *v
ep.mu.Unlock()
return nil
default:
return tcpip.ErrUnknownProtocolOption
}
@ -376,16 +368,7 @@ func (ep *endpoint) LastError() *tcpip.Error {
// GetSockOpt implements tcpip.Endpoint.GetSockOpt.
func (ep *endpoint) GetSockOpt(opt tcpip.GettableSocketOption) *tcpip.Error {
switch o := opt.(type) {
case *tcpip.LingerOption:
ep.mu.Lock()
*o = ep.linger
ep.mu.Unlock()
return nil
default:
return tcpip.ErrNotSupported
}
return tcpip.ErrNotSupported
}
// GetSockOptInt implements tcpip.Endpoint.GetSockOptInt.

View File

@ -85,8 +85,6 @@ type endpoint struct {
// Connect(), and is valid only when conneted is true.
route *stack.Route `state:"manual"`
stats tcpip.TransportEndpointStats `state:"nosave"`
// linger is used for SO_LINGER socket option.
linger tcpip.LingerOption
// owner is used to get uid and gid of the packet.
owner tcpip.PacketOwner
@ -532,16 +530,10 @@ func (e *endpoint) Readiness(mask waiter.EventMask) waiter.EventMask {
// SetSockOpt implements tcpip.Endpoint.SetSockOpt.
func (e *endpoint) SetSockOpt(opt tcpip.SettableSocketOption) *tcpip.Error {
switch v := opt.(type) {
switch opt.(type) {
case *tcpip.SocketDetachFilterOption:
return nil
case *tcpip.LingerOption:
e.mu.Lock()
e.linger = *v
e.mu.Unlock()
return nil
default:
return tcpip.ErrUnknownProtocolOption
}
@ -593,16 +585,7 @@ func (e *endpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) *tcpip.Error {
// GetSockOpt implements tcpip.Endpoint.GetSockOpt.
func (e *endpoint) GetSockOpt(opt tcpip.GettableSocketOption) *tcpip.Error {
switch o := opt.(type) {
case *tcpip.LingerOption:
e.mu.Lock()
*o = e.linger
e.mu.Unlock()
return nil
default:
return tcpip.ErrUnknownProtocolOption
}
return tcpip.ErrUnknownProtocolOption
}
// GetSockOptInt implements tcpip.Endpoint.GetSockOptInt.

View File

@ -674,9 +674,6 @@ 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
// ops is used to get socket level options.
ops tcpip.SocketOptions
}
@ -1040,7 +1037,8 @@ func (e *endpoint) Close() {
return
}
if e.linger.Enabled && e.linger.Timeout == 0 {
linger := e.SocketOptions().GetLinger()
if linger.Enabled && linger.Timeout == 0 {
s := e.EndpointState()
isResetState := s == StateEstablished || s == StateCloseWait || s == StateFinWait1 || s == StateFinWait2 || s == StateSynRecv
if isResetState {
@ -1906,11 +1904,6 @@ func (e *endpoint) SetSockOpt(opt tcpip.SettableSocketOption) *tcpip.Error {
case *tcpip.SocketDetachFilterOption:
return nil
case *tcpip.LingerOption:
e.LockUser()
e.linger = *v
e.UnlockUser()
default:
return nil
}
@ -2071,11 +2064,6 @@ func (e *endpoint) GetSockOpt(opt tcpip.GettableSocketOption) *tcpip.Error {
Port: port,
}
case *tcpip.LingerOption:
e.LockUser()
*o = e.linger
e.UnlockUser()
default:
return tcpip.ErrUnknownProtocolOption
}

View File

@ -144,9 +144,6 @@ 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
// ops is used to get socket level options.
ops tcpip.SocketOptions
}
@ -768,11 +765,6 @@ func (e *endpoint) SetSockOpt(opt tcpip.SettableSocketOption) *tcpip.Error {
case *tcpip.SocketDetachFilterOption:
return nil
case *tcpip.LingerOption:
e.mu.Lock()
e.linger = *v
e.mu.Unlock()
}
return nil
}
@ -851,11 +843,6 @@ func (e *endpoint) GetSockOpt(opt tcpip.GettableSocketOption) *tcpip.Error {
*o = tcpip.BindToDeviceOption(e.bindToDevice)
e.mu.RUnlock()
case *tcpip.LingerOption:
e.mu.RLock()
*o = e.linger
e.mu.RUnlock()
default:
return tcpip.ErrUnknownProtocolOption
}