Move SO_LINGER option to socketops.
PiperOrigin-RevId: 347437786
This commit is contained in:
parent
65e4ed8fbe
commit
2e191cb3f7
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue