774 lines
24 KiB
Go
774 lines
24 KiB
Go
// Copyright 2020 The gVisor Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package tcpip
|
|
|
|
import (
|
|
"gvisor.dev/gvisor/pkg/atomicbitops"
|
|
"gvisor.dev/gvisor/pkg/buffer"
|
|
"gvisor.dev/gvisor/pkg/sync"
|
|
)
|
|
|
|
// SocketOptionsHandler holds methods that help define endpoint specific
|
|
// behavior for socket level socket options. These must be implemented by
|
|
// endpoints to get notified when socket level options are set.
|
|
type SocketOptionsHandler interface {
|
|
// OnReuseAddressSet is invoked when SO_REUSEADDR is set for an endpoint.
|
|
OnReuseAddressSet(v bool)
|
|
|
|
// OnReusePortSet is invoked when SO_REUSEPORT is set for an endpoint.
|
|
OnReusePortSet(v bool)
|
|
|
|
// OnKeepAliveSet is invoked when SO_KEEPALIVE is set for an endpoint.
|
|
OnKeepAliveSet(v bool)
|
|
|
|
// OnDelayOptionSet is invoked when TCP_NODELAY is set for an endpoint.
|
|
// Note that v will be the inverse of TCP_NODELAY option.
|
|
OnDelayOptionSet(v bool)
|
|
|
|
// OnCorkOptionSet is invoked when TCP_CORK is set for an endpoint.
|
|
OnCorkOptionSet(v bool)
|
|
|
|
// LastError is invoked when SO_ERROR is read for an endpoint.
|
|
LastError() Error
|
|
|
|
// UpdateLastError updates the endpoint specific last error field.
|
|
UpdateLastError(err Error)
|
|
|
|
// HasNIC is invoked to check if the NIC is valid for SO_BINDTODEVICE.
|
|
HasNIC(v int32) bool
|
|
|
|
// OnSetSendBufferSize is invoked when the send buffer size for an endpoint is
|
|
// changed. The handler is invoked with the new value for the socket send
|
|
// buffer size. It also returns the newly set value.
|
|
OnSetSendBufferSize(v int64) (newSz int64)
|
|
|
|
// OnSetReceiveBufferSize is invoked by SO_RCVBUF and SO_RCVBUFFORCE. The
|
|
// handler can optionally return a callback which will be called after
|
|
// the buffer size is updated to newSz.
|
|
OnSetReceiveBufferSize(v, oldSz int64) (newSz int64, postSet func())
|
|
|
|
// WakeupWriters is invoked when the send buffer size for an endpoint is
|
|
// changed. The handler notifies the writers if the send buffer size is
|
|
// increased with setsockopt(2) for TCP endpoints.
|
|
WakeupWriters()
|
|
|
|
// GetAcceptConn returns true if the socket is a TCP socket and is in
|
|
// listening state.
|
|
GetAcceptConn() bool
|
|
}
|
|
|
|
// DefaultSocketOptionsHandler is an embeddable type that implements no-op
|
|
// implementations for SocketOptionsHandler methods.
|
|
type DefaultSocketOptionsHandler struct{}
|
|
|
|
var _ SocketOptionsHandler = (*DefaultSocketOptionsHandler)(nil)
|
|
|
|
// OnReuseAddressSet implements SocketOptionsHandler.OnReuseAddressSet.
|
|
func (*DefaultSocketOptionsHandler) OnReuseAddressSet(bool) {}
|
|
|
|
// OnReusePortSet implements SocketOptionsHandler.OnReusePortSet.
|
|
func (*DefaultSocketOptionsHandler) OnReusePortSet(bool) {}
|
|
|
|
// OnKeepAliveSet implements SocketOptionsHandler.OnKeepAliveSet.
|
|
func (*DefaultSocketOptionsHandler) OnKeepAliveSet(bool) {}
|
|
|
|
// OnDelayOptionSet implements SocketOptionsHandler.OnDelayOptionSet.
|
|
func (*DefaultSocketOptionsHandler) OnDelayOptionSet(bool) {}
|
|
|
|
// OnCorkOptionSet implements SocketOptionsHandler.OnCorkOptionSet.
|
|
func (*DefaultSocketOptionsHandler) OnCorkOptionSet(bool) {}
|
|
|
|
// LastError implements SocketOptionsHandler.LastError.
|
|
func (*DefaultSocketOptionsHandler) LastError() Error {
|
|
return nil
|
|
}
|
|
|
|
// UpdateLastError implements SocketOptionsHandler.UpdateLastError.
|
|
func (*DefaultSocketOptionsHandler) UpdateLastError(Error) {}
|
|
|
|
// HasNIC implements SocketOptionsHandler.HasNIC.
|
|
func (*DefaultSocketOptionsHandler) HasNIC(int32) bool {
|
|
return false
|
|
}
|
|
|
|
// OnSetSendBufferSize implements SocketOptionsHandler.OnSetSendBufferSize.
|
|
func (*DefaultSocketOptionsHandler) OnSetSendBufferSize(v int64) (newSz int64) {
|
|
return v
|
|
}
|
|
|
|
// WakeupWriters implements SocketOptionsHandler.WakeupWriters.
|
|
func (*DefaultSocketOptionsHandler) WakeupWriters() {}
|
|
|
|
// OnSetReceiveBufferSize implements SocketOptionsHandler.OnSetReceiveBufferSize.
|
|
func (*DefaultSocketOptionsHandler) OnSetReceiveBufferSize(v, oldSz int64) (newSz int64, postSet func()) {
|
|
return v, nil
|
|
}
|
|
|
|
// GetAcceptConn implements SocketOptionsHandler.GetAcceptConn.
|
|
func (*DefaultSocketOptionsHandler) GetAcceptConn() bool {
|
|
return false
|
|
}
|
|
|
|
// StackHandler holds methods to access the stack options. These must be
|
|
// implemented by the stack.
|
|
type StackHandler interface {
|
|
// Option allows retrieving stack wide options.
|
|
Option(option any) Error
|
|
|
|
// TransportProtocolOption allows retrieving individual protocol level
|
|
// option values.
|
|
TransportProtocolOption(proto TransportProtocolNumber, option GettableTransportProtocolOption) Error
|
|
}
|
|
|
|
// SocketOptions contains all the variables which store values for SOL_SOCKET,
|
|
// SOL_IP, SOL_IPV6 and SOL_TCP level options.
|
|
//
|
|
// +stateify savable
|
|
type SocketOptions struct {
|
|
handler SocketOptionsHandler
|
|
|
|
// StackHandler is initialized at the creation time and will not change.
|
|
stackHandler StackHandler `state:"manual"`
|
|
|
|
// These fields are accessed and modified using atomic operations.
|
|
|
|
// broadcastEnabled determines whether datagram sockets are allowed to
|
|
// send packets to a broadcast address.
|
|
broadcastEnabled atomicbitops.Uint32
|
|
|
|
// passCredEnabled determines whether SCM_CREDENTIALS socket control
|
|
// messages are enabled.
|
|
passCredEnabled atomicbitops.Uint32
|
|
|
|
// noChecksumEnabled determines whether UDP checksum is disabled while
|
|
// transmitting for this socket.
|
|
noChecksumEnabled atomicbitops.Uint32
|
|
|
|
// reuseAddressEnabled determines whether Bind() should allow reuse of
|
|
// local address.
|
|
reuseAddressEnabled atomicbitops.Uint32
|
|
|
|
// reusePortEnabled determines whether to permit multiple sockets to be
|
|
// bound to an identical socket address.
|
|
reusePortEnabled atomicbitops.Uint32
|
|
|
|
// keepAliveEnabled determines whether TCP keepalive is enabled for this
|
|
// socket.
|
|
keepAliveEnabled atomicbitops.Uint32
|
|
|
|
// multicastLoopEnabled determines whether multicast packets sent over a
|
|
// non-loopback interface will be looped back.
|
|
multicastLoopEnabled atomicbitops.Uint32
|
|
|
|
// receiveTOSEnabled is used to specify if the TOS ancillary message is
|
|
// passed with incoming packets.
|
|
receiveTOSEnabled atomicbitops.Uint32
|
|
|
|
// receiveTTLEnabled is used to specify if the TTL ancillary message is passed
|
|
// with incoming packets.
|
|
receiveTTLEnabled atomicbitops.Uint32
|
|
|
|
// receiveHopLimitEnabled is used to specify if the HopLimit ancillary message
|
|
// is passed with incoming packets.
|
|
receiveHopLimitEnabled atomicbitops.Uint32
|
|
|
|
// receiveTClassEnabled is used to specify if the IPV6_TCLASS ancillary
|
|
// message is passed with incoming packets.
|
|
receiveTClassEnabled atomicbitops.Uint32
|
|
|
|
// receivePacketInfoEnabled is used to specify if more information is
|
|
// provided with incoming IPv4 packets.
|
|
receivePacketInfoEnabled atomicbitops.Uint32
|
|
|
|
// receivePacketInfoEnabled is used to specify if more information is
|
|
// provided with incoming IPv6 packets.
|
|
receiveIPv6PacketInfoEnabled atomicbitops.Uint32
|
|
|
|
// hdrIncludeEnabled is used to indicate for a raw endpoint that all packets
|
|
// being written have an IP header and the endpoint should not attach an IP
|
|
// header.
|
|
hdrIncludedEnabled atomicbitops.Uint32
|
|
|
|
// v6OnlyEnabled is used to determine whether an IPv6 socket is to be
|
|
// restricted to sending and receiving IPv6 packets only.
|
|
v6OnlyEnabled atomicbitops.Uint32
|
|
|
|
// quickAckEnabled is used to represent the value of TCP_QUICKACK option.
|
|
// It currently does not have any effect on the TCP endpoint.
|
|
quickAckEnabled atomicbitops.Uint32
|
|
|
|
// delayOptionEnabled is used to specify if data should be sent out immediately
|
|
// by the transport protocol. For TCP, it determines if the Nagle algorithm
|
|
// is on or off.
|
|
delayOptionEnabled atomicbitops.Uint32
|
|
|
|
// corkOptionEnabled is used to specify if data should be held until segments
|
|
// are full by the TCP transport protocol.
|
|
corkOptionEnabled atomicbitops.Uint32
|
|
|
|
// receiveOriginalDstAddress is used to specify if the original destination of
|
|
// the incoming packet should be returned as an ancillary message.
|
|
receiveOriginalDstAddress atomicbitops.Uint32
|
|
|
|
// ipv4RecvErrEnabled determines whether extended reliable error message
|
|
// passing is enabled for IPv4.
|
|
ipv4RecvErrEnabled atomicbitops.Uint32
|
|
|
|
// ipv6RecvErrEnabled determines whether extended reliable error message
|
|
// passing is enabled for IPv6.
|
|
ipv6RecvErrEnabled atomicbitops.Uint32
|
|
|
|
// errQueue is the per-socket error queue. It is protected by errQueueMu.
|
|
errQueueMu sync.Mutex `state:"nosave"`
|
|
errQueue sockErrorList
|
|
|
|
// bindToDevice determines the device to which the socket is bound.
|
|
bindToDevice atomicbitops.Int32
|
|
|
|
// getSendBufferLimits provides the handler to get the min, default and max
|
|
// size for send buffer. It is initialized at the creation time and will not
|
|
// change.
|
|
getSendBufferLimits GetSendBufferLimits `state:"manual"`
|
|
|
|
// sendBufferSize determines the send buffer size for this socket.
|
|
sendBufferSize atomicbitops.Int64
|
|
|
|
// getReceiveBufferLimits provides the handler to get the min, default and
|
|
// max size for receive buffer. It is initialized at the creation time and
|
|
// will not change.
|
|
getReceiveBufferLimits GetReceiveBufferLimits `state:"manual"`
|
|
|
|
// receiveBufferSize determines the receive buffer size for this socket.
|
|
receiveBufferSize atomicbitops.Int64
|
|
|
|
// 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
|
|
|
|
// rcvlowat specifies the minimum number of bytes which should be
|
|
// received to indicate the socket as readable.
|
|
rcvlowat atomicbitops.Int32
|
|
|
|
// experimentOptionValue is the value set for the IP option experiment header
|
|
// if it is not zero.
|
|
experimentOptionValue atomicbitops.Uint32
|
|
}
|
|
|
|
// InitHandler initializes the handler. This must be called before using the
|
|
// socket options utility.
|
|
func (so *SocketOptions) InitHandler(handler SocketOptionsHandler, stack StackHandler, getSendBufferLimits GetSendBufferLimits, getReceiveBufferLimits GetReceiveBufferLimits) {
|
|
so.handler = handler
|
|
so.stackHandler = stack
|
|
so.getSendBufferLimits = getSendBufferLimits
|
|
so.getReceiveBufferLimits = getReceiveBufferLimits
|
|
}
|
|
|
|
func storeAtomicBool(addr *atomicbitops.Uint32, v bool) {
|
|
var val uint32
|
|
if v {
|
|
val = 1
|
|
}
|
|
addr.Store(val)
|
|
}
|
|
|
|
// SetLastError sets the last error for a socket.
|
|
func (so *SocketOptions) SetLastError(err Error) {
|
|
so.handler.UpdateLastError(err)
|
|
}
|
|
|
|
// GetBroadcast gets value for SO_BROADCAST option.
|
|
func (so *SocketOptions) GetBroadcast() bool {
|
|
return so.broadcastEnabled.Load() != 0
|
|
}
|
|
|
|
// SetBroadcast sets value for SO_BROADCAST option.
|
|
func (so *SocketOptions) SetBroadcast(v bool) {
|
|
storeAtomicBool(&so.broadcastEnabled, v)
|
|
}
|
|
|
|
// GetPassCred gets value for SO_PASSCRED option.
|
|
func (so *SocketOptions) GetPassCred() bool {
|
|
return so.passCredEnabled.Load() != 0
|
|
}
|
|
|
|
// SetPassCred sets value for SO_PASSCRED option.
|
|
func (so *SocketOptions) SetPassCred(v bool) {
|
|
storeAtomicBool(&so.passCredEnabled, v)
|
|
}
|
|
|
|
// GetNoChecksum gets value for SO_NO_CHECK option.
|
|
func (so *SocketOptions) GetNoChecksum() bool {
|
|
return so.noChecksumEnabled.Load() != 0
|
|
}
|
|
|
|
// SetNoChecksum sets value for SO_NO_CHECK option.
|
|
func (so *SocketOptions) SetNoChecksum(v bool) {
|
|
storeAtomicBool(&so.noChecksumEnabled, v)
|
|
}
|
|
|
|
// GetReuseAddress gets value for SO_REUSEADDR option.
|
|
func (so *SocketOptions) GetReuseAddress() bool {
|
|
return so.reuseAddressEnabled.Load() != 0
|
|
}
|
|
|
|
// SetReuseAddress sets value for SO_REUSEADDR option.
|
|
func (so *SocketOptions) SetReuseAddress(v bool) {
|
|
storeAtomicBool(&so.reuseAddressEnabled, v)
|
|
so.handler.OnReuseAddressSet(v)
|
|
}
|
|
|
|
// GetReusePort gets value for SO_REUSEPORT option.
|
|
func (so *SocketOptions) GetReusePort() bool {
|
|
return so.reusePortEnabled.Load() != 0
|
|
}
|
|
|
|
// SetReusePort sets value for SO_REUSEPORT option.
|
|
func (so *SocketOptions) SetReusePort(v bool) {
|
|
storeAtomicBool(&so.reusePortEnabled, v)
|
|
so.handler.OnReusePortSet(v)
|
|
}
|
|
|
|
// GetKeepAlive gets value for SO_KEEPALIVE option.
|
|
func (so *SocketOptions) GetKeepAlive() bool {
|
|
return so.keepAliveEnabled.Load() != 0
|
|
}
|
|
|
|
// SetKeepAlive sets value for SO_KEEPALIVE option.
|
|
func (so *SocketOptions) SetKeepAlive(v bool) {
|
|
storeAtomicBool(&so.keepAliveEnabled, v)
|
|
so.handler.OnKeepAliveSet(v)
|
|
}
|
|
|
|
// GetMulticastLoop gets value for IP_MULTICAST_LOOP option.
|
|
func (so *SocketOptions) GetMulticastLoop() bool {
|
|
return so.multicastLoopEnabled.Load() != 0
|
|
}
|
|
|
|
// SetMulticastLoop sets value for IP_MULTICAST_LOOP option.
|
|
func (so *SocketOptions) SetMulticastLoop(v bool) {
|
|
storeAtomicBool(&so.multicastLoopEnabled, v)
|
|
}
|
|
|
|
// GetReceiveTOS gets value for IP_RECVTOS option.
|
|
func (so *SocketOptions) GetReceiveTOS() bool {
|
|
return so.receiveTOSEnabled.Load() != 0
|
|
}
|
|
|
|
// SetReceiveTOS sets value for IP_RECVTOS option.
|
|
func (so *SocketOptions) SetReceiveTOS(v bool) {
|
|
storeAtomicBool(&so.receiveTOSEnabled, v)
|
|
}
|
|
|
|
// GetReceiveTTL gets value for IP_RECVTTL option.
|
|
func (so *SocketOptions) GetReceiveTTL() bool {
|
|
return so.receiveTTLEnabled.Load() != 0
|
|
}
|
|
|
|
// SetReceiveTTL sets value for IP_RECVTTL option.
|
|
func (so *SocketOptions) SetReceiveTTL(v bool) {
|
|
storeAtomicBool(&so.receiveTTLEnabled, v)
|
|
}
|
|
|
|
// GetReceiveHopLimit gets value for IP_RECVHOPLIMIT option.
|
|
func (so *SocketOptions) GetReceiveHopLimit() bool {
|
|
return so.receiveHopLimitEnabled.Load() != 0
|
|
}
|
|
|
|
// SetReceiveHopLimit sets value for IP_RECVHOPLIMIT option.
|
|
func (so *SocketOptions) SetReceiveHopLimit(v bool) {
|
|
storeAtomicBool(&so.receiveHopLimitEnabled, v)
|
|
}
|
|
|
|
// GetReceiveTClass gets value for IPV6_RECVTCLASS option.
|
|
func (so *SocketOptions) GetReceiveTClass() bool {
|
|
return so.receiveTClassEnabled.Load() != 0
|
|
}
|
|
|
|
// SetReceiveTClass sets value for IPV6_RECVTCLASS option.
|
|
func (so *SocketOptions) SetReceiveTClass(v bool) {
|
|
storeAtomicBool(&so.receiveTClassEnabled, v)
|
|
}
|
|
|
|
// GetReceivePacketInfo gets value for IP_PKTINFO option.
|
|
func (so *SocketOptions) GetReceivePacketInfo() bool {
|
|
return so.receivePacketInfoEnabled.Load() != 0
|
|
}
|
|
|
|
// SetReceivePacketInfo sets value for IP_PKTINFO option.
|
|
func (so *SocketOptions) SetReceivePacketInfo(v bool) {
|
|
storeAtomicBool(&so.receivePacketInfoEnabled, v)
|
|
}
|
|
|
|
// GetIPv6ReceivePacketInfo gets value for IPV6_RECVPKTINFO option.
|
|
func (so *SocketOptions) GetIPv6ReceivePacketInfo() bool {
|
|
return so.receiveIPv6PacketInfoEnabled.Load() != 0
|
|
}
|
|
|
|
// SetIPv6ReceivePacketInfo sets value for IPV6_RECVPKTINFO option.
|
|
func (so *SocketOptions) SetIPv6ReceivePacketInfo(v bool) {
|
|
storeAtomicBool(&so.receiveIPv6PacketInfoEnabled, v)
|
|
}
|
|
|
|
// GetHeaderIncluded gets value for IP_HDRINCL option.
|
|
func (so *SocketOptions) GetHeaderIncluded() bool {
|
|
return so.hdrIncludedEnabled.Load() != 0
|
|
}
|
|
|
|
// SetHeaderIncluded sets value for IP_HDRINCL option.
|
|
func (so *SocketOptions) SetHeaderIncluded(v bool) {
|
|
storeAtomicBool(&so.hdrIncludedEnabled, v)
|
|
}
|
|
|
|
// GetV6Only gets value for IPV6_V6ONLY option.
|
|
func (so *SocketOptions) GetV6Only() bool {
|
|
return so.v6OnlyEnabled.Load() != 0
|
|
}
|
|
|
|
// SetV6Only sets value for IPV6_V6ONLY option.
|
|
//
|
|
// Preconditions: the backing TCP or UDP endpoint must be in initial state.
|
|
func (so *SocketOptions) SetV6Only(v bool) {
|
|
storeAtomicBool(&so.v6OnlyEnabled, v)
|
|
}
|
|
|
|
// GetQuickAck gets value for TCP_QUICKACK option.
|
|
func (so *SocketOptions) GetQuickAck() bool {
|
|
return so.quickAckEnabled.Load() != 0
|
|
}
|
|
|
|
// SetQuickAck sets value for TCP_QUICKACK option.
|
|
func (so *SocketOptions) SetQuickAck(v bool) {
|
|
storeAtomicBool(&so.quickAckEnabled, v)
|
|
}
|
|
|
|
// GetDelayOption gets inverted value for TCP_NODELAY option.
|
|
func (so *SocketOptions) GetDelayOption() bool {
|
|
return so.delayOptionEnabled.Load() != 0
|
|
}
|
|
|
|
// SetDelayOption sets inverted value for TCP_NODELAY option.
|
|
func (so *SocketOptions) SetDelayOption(v bool) {
|
|
storeAtomicBool(&so.delayOptionEnabled, v)
|
|
so.handler.OnDelayOptionSet(v)
|
|
}
|
|
|
|
// GetCorkOption gets value for TCP_CORK option.
|
|
func (so *SocketOptions) GetCorkOption() bool {
|
|
return so.corkOptionEnabled.Load() != 0
|
|
}
|
|
|
|
// SetCorkOption sets value for TCP_CORK option.
|
|
func (so *SocketOptions) SetCorkOption(v bool) {
|
|
storeAtomicBool(&so.corkOptionEnabled, v)
|
|
so.handler.OnCorkOptionSet(v)
|
|
}
|
|
|
|
// GetReceiveOriginalDstAddress gets value for IP(V6)_RECVORIGDSTADDR option.
|
|
func (so *SocketOptions) GetReceiveOriginalDstAddress() bool {
|
|
return so.receiveOriginalDstAddress.Load() != 0
|
|
}
|
|
|
|
// SetReceiveOriginalDstAddress sets value for IP(V6)_RECVORIGDSTADDR option.
|
|
func (so *SocketOptions) SetReceiveOriginalDstAddress(v bool) {
|
|
storeAtomicBool(&so.receiveOriginalDstAddress, v)
|
|
}
|
|
|
|
// GetIPv4RecvError gets value for IP_RECVERR option.
|
|
func (so *SocketOptions) GetIPv4RecvError() bool {
|
|
return so.ipv4RecvErrEnabled.Load() != 0
|
|
}
|
|
|
|
// SetIPv4RecvError sets value for IP_RECVERR option.
|
|
func (so *SocketOptions) SetIPv4RecvError(v bool) {
|
|
storeAtomicBool(&so.ipv4RecvErrEnabled, v)
|
|
if !v {
|
|
so.pruneErrQueue()
|
|
}
|
|
}
|
|
|
|
// GetIPv6RecvError gets value for IPV6_RECVERR option.
|
|
func (so *SocketOptions) GetIPv6RecvError() bool {
|
|
return so.ipv6RecvErrEnabled.Load() != 0
|
|
}
|
|
|
|
// SetIPv6RecvError sets value for IPV6_RECVERR option.
|
|
func (so *SocketOptions) SetIPv6RecvError(v bool) {
|
|
storeAtomicBool(&so.ipv6RecvErrEnabled, v)
|
|
if !v {
|
|
so.pruneErrQueue()
|
|
}
|
|
}
|
|
|
|
// GetLastError gets value for SO_ERROR option.
|
|
func (so *SocketOptions) GetLastError() Error {
|
|
return so.handler.LastError()
|
|
}
|
|
|
|
// GetOutOfBandInline gets value for SO_OOBINLINE option.
|
|
func (*SocketOptions) GetOutOfBandInline() bool {
|
|
return true
|
|
}
|
|
|
|
// 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()
|
|
}
|
|
|
|
// GetExperimentOptionValue gets value for the experiment IP option header.
|
|
func (so *SocketOptions) GetExperimentOptionValue() uint16 {
|
|
v := so.experimentOptionValue.Load()
|
|
return uint16(v)
|
|
}
|
|
|
|
// SetExperimentOptionValue sets the value for the experiment IP option header.
|
|
func (so *SocketOptions) SetExperimentOptionValue(v uint16) {
|
|
so.experimentOptionValue.Store(uint32(v))
|
|
}
|
|
|
|
// SockErrOrigin represents the constants for error origin.
|
|
type SockErrOrigin uint8
|
|
|
|
const (
|
|
// SockExtErrorOriginNone represents an unknown error origin.
|
|
SockExtErrorOriginNone SockErrOrigin = iota
|
|
|
|
// SockExtErrorOriginLocal indicates a local error.
|
|
SockExtErrorOriginLocal
|
|
|
|
// SockExtErrorOriginICMP indicates an IPv4 ICMP error.
|
|
SockExtErrorOriginICMP
|
|
|
|
// SockExtErrorOriginICMP6 indicates an IPv6 ICMP error.
|
|
SockExtErrorOriginICMP6
|
|
)
|
|
|
|
// IsICMPErr indicates if the error originated from an ICMP error.
|
|
func (origin SockErrOrigin) IsICMPErr() bool {
|
|
return origin == SockExtErrorOriginICMP || origin == SockExtErrorOriginICMP6
|
|
}
|
|
|
|
// SockErrorCause is the cause of a socket error.
|
|
type SockErrorCause interface {
|
|
// Origin is the source of the error.
|
|
Origin() SockErrOrigin
|
|
|
|
// Type is the origin specific type of error.
|
|
Type() uint8
|
|
|
|
// Code is the origin and type specific error code.
|
|
Code() uint8
|
|
|
|
// Info is any extra information about the error.
|
|
Info() uint32
|
|
}
|
|
|
|
// LocalSockError is a socket error that originated from the local host.
|
|
//
|
|
// +stateify savable
|
|
type LocalSockError struct {
|
|
info uint32
|
|
}
|
|
|
|
// Origin implements SockErrorCause.
|
|
func (*LocalSockError) Origin() SockErrOrigin {
|
|
return SockExtErrorOriginLocal
|
|
}
|
|
|
|
// Type implements SockErrorCause.
|
|
func (*LocalSockError) Type() uint8 {
|
|
return 0
|
|
}
|
|
|
|
// Code implements SockErrorCause.
|
|
func (*LocalSockError) Code() uint8 {
|
|
return 0
|
|
}
|
|
|
|
// Info implements SockErrorCause.
|
|
func (l *LocalSockError) Info() uint32 {
|
|
return l.info
|
|
}
|
|
|
|
// SockError represents a queue entry in the per-socket error queue.
|
|
//
|
|
// +stateify savable
|
|
type SockError struct {
|
|
sockErrorEntry
|
|
|
|
// Err is the error caused by the errant packet.
|
|
Err Error
|
|
// Cause is the detailed cause of the error.
|
|
Cause SockErrorCause
|
|
|
|
// Payload is the errant packet's payload.
|
|
Payload *buffer.View
|
|
// Dst is the original destination address of the errant packet.
|
|
Dst FullAddress
|
|
// Offender is the original sender address of the errant packet.
|
|
Offender FullAddress
|
|
// NetProto is the network protocol being used to transmit the packet.
|
|
NetProto NetworkProtocolNumber
|
|
}
|
|
|
|
// pruneErrQueue resets the queue.
|
|
func (so *SocketOptions) pruneErrQueue() {
|
|
so.errQueueMu.Lock()
|
|
so.errQueue.Reset()
|
|
so.errQueueMu.Unlock()
|
|
}
|
|
|
|
// DequeueErr dequeues a socket extended error from the error queue and returns
|
|
// it. Returns nil if queue is empty.
|
|
func (so *SocketOptions) DequeueErr() *SockError {
|
|
so.errQueueMu.Lock()
|
|
defer so.errQueueMu.Unlock()
|
|
|
|
err := so.errQueue.Front()
|
|
if err != nil {
|
|
so.errQueue.Remove(err)
|
|
}
|
|
return err
|
|
}
|
|
|
|
// PeekErr returns the error in the front of the error queue. Returns nil if
|
|
// the error queue is empty.
|
|
func (so *SocketOptions) PeekErr() *SockError {
|
|
so.errQueueMu.Lock()
|
|
defer so.errQueueMu.Unlock()
|
|
return so.errQueue.Front()
|
|
}
|
|
|
|
// QueueErr inserts the error at the back of the error queue.
|
|
//
|
|
// Preconditions: so.GetIPv4RecvError() or so.GetIPv6RecvError() is true.
|
|
func (so *SocketOptions) QueueErr(err *SockError) {
|
|
so.errQueueMu.Lock()
|
|
defer so.errQueueMu.Unlock()
|
|
so.errQueue.PushBack(err)
|
|
}
|
|
|
|
// QueueLocalErr queues a local error onto the local queue.
|
|
func (so *SocketOptions) QueueLocalErr(err Error, net NetworkProtocolNumber, info uint32, dst FullAddress, payload *buffer.View) {
|
|
so.QueueErr(&SockError{
|
|
Err: err,
|
|
Cause: &LocalSockError{info: info},
|
|
Payload: payload,
|
|
Dst: dst,
|
|
NetProto: net,
|
|
})
|
|
}
|
|
|
|
// GetBindToDevice gets value for SO_BINDTODEVICE option.
|
|
func (so *SocketOptions) GetBindToDevice() int32 {
|
|
return so.bindToDevice.Load()
|
|
}
|
|
|
|
// SetBindToDevice sets value for SO_BINDTODEVICE option. If bindToDevice is
|
|
// zero, the socket device binding is removed.
|
|
func (so *SocketOptions) SetBindToDevice(bindToDevice int32) Error {
|
|
if bindToDevice != 0 && !so.handler.HasNIC(bindToDevice) {
|
|
return &ErrUnknownDevice{}
|
|
}
|
|
|
|
so.bindToDevice.Store(bindToDevice)
|
|
return nil
|
|
}
|
|
|
|
// GetSendBufferSize gets value for SO_SNDBUF option.
|
|
func (so *SocketOptions) GetSendBufferSize() int64 {
|
|
return so.sendBufferSize.Load()
|
|
}
|
|
|
|
// SendBufferLimits returns the [min, max) range of allowable send buffer
|
|
// sizes.
|
|
func (so *SocketOptions) SendBufferLimits() (min, max int64) {
|
|
limits := so.getSendBufferLimits(so.stackHandler)
|
|
return int64(limits.Min), int64(limits.Max)
|
|
}
|
|
|
|
// SetSendBufferSize sets value for SO_SNDBUF option. notify indicates if the
|
|
// stack handler should be invoked to set the send buffer size.
|
|
func (so *SocketOptions) SetSendBufferSize(sendBufferSize int64, notify bool) {
|
|
if notify {
|
|
sendBufferSize = so.handler.OnSetSendBufferSize(sendBufferSize)
|
|
}
|
|
so.sendBufferSize.Store(sendBufferSize)
|
|
if notify {
|
|
so.handler.WakeupWriters()
|
|
}
|
|
}
|
|
|
|
// GetReceiveBufferSize gets value for SO_RCVBUF option.
|
|
func (so *SocketOptions) GetReceiveBufferSize() int64 {
|
|
return so.receiveBufferSize.Load()
|
|
}
|
|
|
|
// ReceiveBufferLimits returns the [min, max) range of allowable receive buffer
|
|
// sizes.
|
|
func (so *SocketOptions) ReceiveBufferLimits() (min, max int64) {
|
|
limits := so.getReceiveBufferLimits(so.stackHandler)
|
|
return int64(limits.Min), int64(limits.Max)
|
|
}
|
|
|
|
// SetReceiveBufferSize sets the value of the SO_RCVBUF option, optionally
|
|
// notifying the owning endpoint.
|
|
func (so *SocketOptions) SetReceiveBufferSize(receiveBufferSize int64, notify bool) {
|
|
var postSet func()
|
|
if notify {
|
|
oldSz := so.receiveBufferSize.Load()
|
|
receiveBufferSize, postSet = so.handler.OnSetReceiveBufferSize(receiveBufferSize, oldSz)
|
|
}
|
|
so.receiveBufferSize.Store(receiveBufferSize)
|
|
if postSet != nil {
|
|
postSet()
|
|
}
|
|
}
|
|
|
|
// GetRcvlowat gets value for SO_RCVLOWAT option.
|
|
func (so *SocketOptions) GetRcvlowat() int32 {
|
|
// TODO(b/226603727): Return so.rcvlowat after adding complete support
|
|
// for SO_RCVLOWAT option. For now, return the default value of 1.
|
|
defaultRcvlowat := int32(1)
|
|
return defaultRcvlowat
|
|
}
|
|
|
|
// SetRcvlowat sets value for SO_RCVLOWAT option.
|
|
func (so *SocketOptions) SetRcvlowat(rcvlowat int32) Error {
|
|
so.rcvlowat.Store(rcvlowat)
|
|
return nil
|
|
}
|
|
|
|
// GetAcceptConn gets value for SO_ACCEPTCONN option.
|
|
func (so *SocketOptions) GetAcceptConn() bool {
|
|
return so.handler.GetAcceptConn()
|
|
}
|