unet

package
v0.0.0-...-d15fba8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 21, 2024 License: MIT Imports: 21 Imported by: 0

Documentation

Index

Constants

View Source
const (
	InvalidIpv4Str = "192.0.2.1" // RFC5737 - for testing, 192.0.2.0/24
	InvalidIpv6Str = "0100::1"   // RFC6666 - for testing, 0100::/64
)
View Source
const (
	// ICMP v4 types
	//
	// seen, for example, in unix.SockExtendedErr.Type
	ICMP_ECHOREPLY      = 0  // Echo Reply
	ICMP_DEST_UNREACH   = 3  // Destination Unreachable
	ICMP_SOURCE_QUENCH  = 4  // Source Quench
	ICMP_REDIRECT       = 5  // Redirect (change route)
	ICMP_ECHO           = 8  // Echo Request
	ICMP_TIME_EXCEEDED  = 11 // Time Exceeded
	ICMP_PARAMETERPROB  = 12 // Parameter Problem
	ICMP_TIMESTAMP      = 13 // Timestamp Request
	ICMP_TIMESTAMPREPLY = 14 // Timestamp Reply
	ICMP_INFO_REQUEST   = 15 // Information Request
	ICMP_INFO_REPLY     = 16 // Information Reply
	ICMP_ADDRESS        = 17 // Address Mask Request
	ICMP_ADDRESSREPLY   = 18 // Address Mask Reply
	NR_ICMP_TYPES       = 18

	// Codes for ICMP_DEST_UNREACH
	// seen, for example, in unix.SockExtendedErr.Code
	ICMP_NET_UNREACH    = 0 // Network Unreachable
	ICMP_HOST_UNREACH   = 1 // Host Unreachable
	ICMP_PROT_UNREACH   = 2 // Protocol Unreachable
	ICMP_PORT_UNREACH   = 3 // Port Unreachable
	ICMP_FRAG_NEEDED    = 4 // Fragmentation Needed/DF set
	ICMP_SR_FAILED      = 5 // Source Route failed
	ICMP_NET_UNKNOWN    = 6
	ICMP_HOST_UNKNOWN   = 7
	ICMP_HOST_ISOLATED  = 8
	ICMP_NET_ANO        = 9
	ICMP_HOST_ANO       = 10
	ICMP_NET_UNR_TOS    = 11
	ICMP_HOST_UNR_TOS   = 12
	ICMP_PKT_FILTERED   = 13 // Packet filtered
	ICMP_PREC_VIOLATION = 14 // Precedence violation
	ICMP_PREC_CUTOFF    = 15 // Precedence cut off
	NR_ICMP_UNREACH     = 15 // instead of hardcoding immediate value

	// Codes for ICMP_REDIRECT
	ICMP_REDIR_NET     = 0 // Redirect Net
	ICMP_REDIR_HOST    = 1 // Redirect Host
	ICMP_REDIR_NETTOS  = 2 // Redirect Net for TOS
	ICMP_REDIR_HOSTTOS = 3 // Redirect Host for TOS

	// Codes for ICMP_TIME_EXCEEDED
	ICMP_EXC_TTL      = 0 // TTL count exceeded
	ICMP_EXC_FRAGTIME = 1 // Fragment Reass time exceeded
)

see /usr/include/linux/icmp.h

View Source
const (
	// ICMP v6 Types
	ICMPV6_DEST_UNREACH = 1
	ICMPV6_PKT_TOOBIG   = 2
	ICMPV6_TIME_EXCEED  = 3
	ICMPV6_PARAMPROB    = 4

	ICMPV6_ECHO_REQUEST = 128
	ICMPV6_ECHO_REPLY   = 129

	// codes for ICMPV6_DEST_UNREACH
	ICMPV6_NOROUTE        = 0
	ICMPV6_ADM_PROHIBITED = 1
	ICMPV6_NOT_NEIGHBOUR  = 2
	ICMPV6_ADDR_UNREACH   = 3
	ICMPV6_PORT_UNREACH   = 4
	ICMPV6_POLICY_FAIL    = 5
	ICMPV6_REJECT_ROUTE   = 6

	// codes for ICMPV6_TIME_EXCEED
	ICMPV6_EXC_HOPLIMIT = 0
	ICMPV6_EXC_FRAGTIME = 1

	// codes for ICMPV6_PARAMPROB
	ICMPV6_HDR_FIELD   = 0
	ICMPV6_UNK_NEXTHDR = 1
	ICMPV6_UNK_OPTION  = 2
	ICMPV6_HDR_INCOMP  = 3
)

see /usr/include/linux/icmpv6.h

View Source
const (
	MtuMinIpv4  = 576  // RFC 791, but RFC 4821 says 1024 is smallest practical
	MtuMinIpv6  = 1280 // RFC 2460
	MtuMaxJumbo = 9216 // supported by most (all?) equipment, but 9000 common

	//
	// This one needs explanation.
	//
	// IPv4 has a 16 bit length field, but that includes the header and options.
	// The header is 20 bytes, so the payload is a max of 65515 bytes.
	//
	// UDP has a 16 bit length field, so it's max is 65535, but then the IPv4 header
	// added to that would be 65555!  You probably only see something like this
	// for loopback, where likely there is no 'real' ipv4 header.
	//
	// Indeed, loopback often has mtu set at 65536.
	//
	// See also RFC 2675 (jumbograms), which talks about mtu of 65575 for
	// non-jumbograms!  We don't support the notion of jumbograms here.
	//
	// However, with all that in mind, even with loopback mtu of 65536, the highest
	// probed value will be 65535!  This makes sense since largest UDP datagram is
	// 65535.
	//
	MtuMax = 65535
)
View Source
const (
	ErrNotInitialized     = uerr.Const("Not initialized.  Call Construct first.")
	ErrFdDisabled         = uerr.Const("File descriptor disabled")
	ErrFdTransfer         = uerr.Const("Could not transfer file descriptor")
	ErrAlreadyInitialized = uerr.Const("Already initialized")
	ErrNil                = uerr.Const("sock is nil")
)
View Source
const (
	IP_OVERHEAD     = 20
	IP6_OVERHEAD    = 40 // does not include extension headers
	UDP_OVERHEAD    = 8
	IPUDP_OVERHEAD  = IP_OVERHEAD + UDP_OVERHEAD
	IP6UDP_OVERHEAD = IP6_OVERHEAD + UDP_OVERHEAD
	UDP_MAX         = 65535 - IPUDP_OVERHEAD
	UDP_MAX_128     = 65408 // max mult of 128
	JUMBO_MAX_128   = 8960  // max mult of 128 when MTU is 9001
)

some useful values

View Source
const (
	SYS_RECVMMSG uintptr = 299
	SYS_SENDMMSG uintptr = 307
)

from golang.org/x/sys/unix

View Source
const (
	UDP_SEGMENT int = 103
)

from golang.org/x/sys/unix

Variables

This section is empty.

Functions

func AllLocalIps

func AllLocalIps() (rv []net.IP, err error)

get a list of all IP addresses of all network interfaces

func AllowIp4

func AllowIp4(ip net.IP) bool

use with FindLocalIps

func AllowIp6

func AllowIp6(ip net.IP) bool

use with FindLocalIps

func AllowIps

func AllowIps(hosts []string) (filter func(net.IP) bool, err error)

create a filter to match specific hosts

func AllowUnicastIps

func AllowUnicastIps(ip net.IP) bool

only allow normal global unicast ips. so, no loopback.

use with FindLocalIps

func AsSockaddr

func AsSockaddr(ip net.IP, port int) (rv syscall.Sockaddr)

set ip/port to a Sockaddr for ipv4 or ipv6

func CmsgSetupMsghdr

func CmsgSetupMsghdr(msghdr *syscall.Msghdr, cmsgbuff []byte)

helper to setup msghdr for cmsghdrs before calling recvmsg

func DenyLoopbackIps

func DenyLoopbackIps(ip net.IP) bool

deny loopback ips

use with FindLocalIps

func DenyMulticastIps

func DenyMulticastIps(ip net.IP) bool

deny multicast ips

use with FindLocalIps

func DenyPrivateIps

func DenyPrivateIps(ip net.IP) bool

deny private ips, such as 10., 192.168., 172

use with FindLocalIps

func FilterIps

func FilterIps(filter ...func(net.IP) bool) func(net.IP) bool

construct a multi-step filter

use with FindLocalIps

func FindLocalIps

func FindLocalIps(
	allowIntfc func(net.Interface) bool,
	allowIp func(net.IP) bool,
) (
	rv []net.IP,
	err error,
)

get a list of the filtered IP addresses of the filtered network interfaces

setting either filter to nil means to accept all

func GetSocketFd

func GetSocketFd(conn *net.TCPConn) (fd int, f *os.File)

get the underlying file descriptor from the socket. we also have to return the underlying os.File and the caller has to hold onto that or it will be gc'd and the fd will be unusable.

WARNING: after this call, setting deadlines (SetReadDeadline) on conn will no longer work! See: https://github.com/golang/go/issues/7605

NOTE: This call uses dup(), so there will be 2 file descriptors when done

func HelpDscp

func HelpDscp() string

These are the known IP DSCP / TOS names and codes.

func Htonl

func Htonl(v uint32) (rv uint32)

convert uint32 from one byte order to the other

func Htons

func Htons(v uint16) (rv uint16)

convert uint16 from one byte order to the other

func IsSockaddrPortOrIpZero

func IsSockaddrPortOrIpZero(sa syscall.Sockaddr) bool

func IsSockaddrValid

func IsSockaddrValid(sa syscall.Sockaddr) bool

func IsSockaddrZero

func IsSockaddrZero(sa syscall.Sockaddr) bool

func KnownDscpTosCode

func KnownDscpTosCode(code byte) bool

func LookupDscpTos

func LookupDscpTos(value string) (code byte, err error)

DSCP / TOS value: can be one of the known DSCP types or just a numeric.

Valid values that all mean the same thing: - AF42 - by name - 144 - decimal - 0x90 - hex - 0o220 - octal - 0b10010000 - binary

func MMsghdrsAsString

func MMsghdrsAsString(hdrs []MMsghdr) string

func MeansClosed

func MeansClosed(err error) bool

does the error mean that the socket is closed?

this occurs when another goroutine in the same process has closed it to tell the guy using it to go away, like when the component is being turned off.

in some situations errors.Is(syscall.ECONNRESET) is also useful

func NameBytesAsIpAndPort

func NameBytesAsIpAndPort(name *byte, namelen uint32, ip *net.IP) (port int)

Suitable for decoding Name and Namelen of syscall.Msghdr

NOTE: ip is set to the internal bytes of the name buffer

func NameBytesAsSockaddr

func NameBytesAsSockaddr(name *byte, namelen uint32) (rv syscall.Sockaddr, err error)

Suitable for decoding Name and Namelen of syscall.Msghdr

func NameBytesAsString

func NameBytesAsString(name *byte, namelen uint32) (rv string)

Suitable for decoding Name and Namelen of syscall.Msghdr

func RawRecvMMsg

func RawRecvMMsg(fd, hdrs, hdrslen uintptr) (messages int, err syscall.Errno)

func RawSendMMsg

func RawSendMMsg(fd, hdrs, hdrslen uintptr) (nsent int, err syscall.Errno)

func RawSockaddrAsNameBytes

func RawSockaddrAsNameBytes(
	sa syscall.Sockaddr,

	space []byte,
) (
	name *byte,
	namelen uint32,
	err error,
)

Suitable for creating Name and Namelen of syscall.Msghdr

space is necessary to reserve space for the sockaddr type. you must ensure that space is allocated on the heap and is sized appropriately (syscall.SizeofSockaddrInet6)

func RecvMMsg

func RecvMMsg(fd, hdrs, hdrslen uintptr) (messages int, err syscall.Errno)

this barely inlines (budget: 78)

func RecvMsg

func RecvMsg(fd, msghdr, flags uintptr) (nread int, err syscall.Errno)

this barely inlines (budget: 78)

func ResolveIp

func ResolveIp(hostOrIp string, timeout ...time.Duration) (rv net.IP, err error)

resolve host to an ipv4 or ipv6 addr

func ResolveIps

func ResolveIps(hostOrIp string, timeout ...time.Duration) (rv []net.IP, err error)

func ResolveNames

func ResolveNames(ip net.IP, timeout ...time.Duration) (rv []string, err error)

func ResolveSockaddr

func ResolveSockaddr(
	host string,
	port int,
	timeout ...time.Duration,
) (
	rv syscall.Sockaddr,
	err error,
)

resolve host/port to a Sockaddr for ipv4 or ipv6

func ResolveTcp

func ResolveTcp(
	hostOrIp string,
	port int,
	timeout ...time.Duration,
) (
	rv *net.TCPAddr,
	err error,
)

func SendMMsg

func SendMMsg(fd, hdrs, hdrslen uintptr) (nsent int, err syscall.Errno)

this barely inlines (budget: 78)

func SendMMsgRetry

func SendMMsgRetry(
	fd uintptr,
	hdrs []MMsghdr,
	avail int,
) (
	retries int,
	err syscall.Errno,
)

We are making syscall, so we need to take care that parameters we pass will not be gc'd or moved by gc. Easiest way to do that is to ensure that all values are on the heap.

this code is escape optimized

func SendMsg

func SendMsg(fd, hdr, flags uintptr) (nsent int, err syscall.Errno)

this barely inlines (budget: 78)

func SockaddrFamily

func SockaddrFamily(sa syscall.Sockaddr) (rv int, err error)

get socket family of sockaddr

func SockaddrHostPort

func SockaddrHostPort(sa syscall.Sockaddr) string

func SockaddrIP

func SockaddrIP(sa syscall.Sockaddr) net.IP

func SockaddrPort

func SockaddrPort(sa syscall.Sockaddr) int

func SysctlGet

func SysctlGet(item string) (rv int64, err error)

equivalent to command line sysctl

func SysctlGetNetCoreRmemMax

func SysctlGetNetCoreRmemMax() (rv int64, err error)

func SysctlGetNetCoreWmemMax

func SysctlGetNetCoreWmemMax() (rv int64, err error)

func ValidDscpTos

func ValidDscpTos(value string) (err error)

uconfig validator

func ValidDscpTosCode

func ValidDscpTosCode(code byte) (err error)

CS7 (0xe0) is the highest known dscp code, but since we operate on some strange networks, we allow values above that

func ValidIp

func ValidIp(hostOrIp string) (err error)

if hostOrIp is not an ip addr and is not resolvable, then error

conforms to uconfig.Validator

Types

type Address

type Address struct {
	// contains filtered or unexported fields
}

a struct that can hold either ipv4 or ipv6 address, plus port

suitable for using as a map key

the net.IP type is a slice, so cannot be used as a key in a map, etc.

When net.IP stores an ipv4 addr, it either does it in a 4 byte slice (uncommon) or as an ip4-in-ip6 address in a 16 bytes slice. That is:

::ffff:a.b.c.d

So, the ipv4 address is in the last 4 bytes of the slice, preceded by ffff.

We use the ip4-in-ip6 method to store all ipv4 as ipv6.

for ipv6, we currently do not support the zone id, as that is primarily for link local addresses, which are not of interest to us.

func ResolveAddrs

func ResolveAddrs(
	hostOrIp string,
	timeout ...time.Duration,
) (
	rv []Address,
	err error,
)

func (*Address) AsIp

func (this *Address) AsIp() (rv net.IP)

func (*Address) AsIpv4

func (this *Address) AsIpv4() (rv net.IP)

func (*Address) AsNameBytes

func (this *Address) AsNameBytes(space []byte) (name *byte, namelen uint32)

Pack addr into provided space, returning name and namelen that point into space. space must be on heap.

Use for syscall.Msghdr (sendmsg/recvmsg)

func (*Address) AsSockaddr

func (this *Address) AsSockaddr() (rv syscall.Sockaddr)

allocate and populate a sockaddr based on this

func (*Address) Clear

func (this *Address) Clear()

func (*Address) ClearIp

func (this *Address) ClearIp()

func (*Address) ClearPort

func (this *Address) ClearPort()

func (*Address) FromHostPort

func (this *Address) FromHostPort(hostOrIp string, port uint16) (err error)

func (*Address) FromIpAndPort

func (this *Address) FromIpAndPort(ip net.IP, port uint16)

func (*Address) FromNameBytes

func (this *Address) FromNameBytes(name *byte, namelen uint32)

see syscall.Msghdr (Name and Namelen fields)

func (*Address) FromSockaddr

func (this *Address) FromSockaddr(sa syscall.Sockaddr)

func (*Address) Ip

func (this *Address) Ip() (rv net.IP)

return an allocated copy of the ip

func (*Address) IsAny

func (this *Address) IsAny() bool

func (Address) IsEitherZero

func (this Address) IsEitherZero() bool

is either ip or port set as zeros? this is not the same as unset!

func (*Address) IsGlobalUnicast

func (this *Address) IsGlobalUnicast() bool

func (Address) IsIpSet

func (this Address) IsIpSet() bool

func (Address) IsIpZero

func (this Address) IsIpZero() bool

is ip set to 0.0.0.0 or ::?

func (Address) IsIpv4

func (this Address) IsIpv4() bool

func (Address) IsIpv4Zero

func (this Address) IsIpv4Zero() bool

is ip set to 0.0.0.0?

func (Address) IsIpv6

func (this Address) IsIpv6() bool

func (Address) IsIpv6Zero

func (this Address) IsIpv6Zero() bool

is ip set to ::?

func (*Address) IsLoopback

func (this *Address) IsLoopback() bool

func (*Address) IsMulticast

func (this *Address) IsMulticast() bool

func (Address) IsPortSet

func (this Address) IsPortSet() bool

func (*Address) IsPrivate

func (this *Address) IsPrivate() bool

func (Address) IsSet

func (this Address) IsSet() bool

are both IP and port set?

func (*Address) IsUnspecified

func (this *Address) IsUnspecified() bool

func (Address) IsZero

func (this Address) IsZero() bool

are both ip and port set as zeros? we also accept unset port as part of zero port this is not the same as unset!

func (Address) Network

func (this Address) Network() string

implement net.Addr

func (Address) Port

func (this Address) Port() uint16

func (*Address) ResolveIp

func (this *Address) ResolveIp(hostOrIp string) (err error)

try to parse hostOrIp, and then try to lookup hostOrIp if that fails. so, if hostOrIp is an IP addr, no lookup will occur

func (*Address) SetAddrFrom

func (this *Address) SetAddrFrom(that Address)

func (*Address) SetIp

func (this *Address) SetIp(ip net.IP)

func (*Address) SetIpFromNetIp

func (this *Address) SetIpFromNetIp(ip netip.Addr)

func (*Address) SetIpFromString

func (this *Address) SetIpFromString(s string) (ok bool)

if s represents an IP address, set from that

func (*Address) SetIpv4Zero

func (this *Address) SetIpv4Zero()

set ip to '0.0.0.0'

func (*Address) SetIpv6Zero

func (this *Address) SetIpv6Zero()

set ip to '::'

func (*Address) SetPort

func (this *Address) SetPort(port uint16)

func (Address) String

func (this Address) String() string

implement net.Addr

func (*Address) ToSockaddr4

func (this *Address) ToSockaddr4(sa *syscall.SockaddrInet4)

populate provided sockaddr based on this

func (*Address) ToSockaddr6

func (this *Address) ToSockaddr6(sa *syscall.SockaddrInet6)

populate provided sockaddr based on this

type CmsgLens

type CmsgLens struct {
	// contains filtered or unexported fields
}

a lens to examine Cmsghdr structs from recvmsg

func (*CmsgLens) First

func (this *CmsgLens) First(msghdr *syscall.Msghdr) (ok bool)

use to check for first Cmsghdr

analog to CMSG_FIRSTHDR()

func (*CmsgLens) IpError

func (this *CmsgLens) IpError() (rv unix.SockExtendedErr, ok bool, err error)

if cmsg is extended error, get it

if rv.Errno == syscall.EMSGSIZE, then rv.Info contains MTU to use

see ip(7) of the linux man pages for more info about IP_RECVERR

see /usr/include/linux/errqueue.h

func (*CmsgLens) IpErrorOffender

func (this *CmsgLens) IpErrorOffender(rv *Address) (ok bool)

use after IpError() is successful to get source of error.

refer to SO_EE_OFFENDER() in ip(7) of linux man pages

func (*CmsgLens) IsIpError

func (this *CmsgLens) IsIpError() bool

func (*CmsgLens) Level

func (this *CmsgLens) Level() int32

func (*CmsgLens) Msg

func (this *CmsgLens) Msg() []byte

func (*CmsgLens) Next

func (this *CmsgLens) Next() (ok bool)

use for subsequent Cmsghdrs

analog to CMSG_NXTHDR()

func (*CmsgLens) PktInfo

func (this *CmsgLens) PktInfo(ipB net.IP) (rv net.IP, ok bool, err error)

Get the target (destination) IP from the Cmsghdr.

When recvmsg or recvmmsg used, Control and Controllen from Msghdr has this.

See TestCmsghdr.

See ip(7) of the linux man pages for more info about IP_PKTINFO.

func (*CmsgLens) Type

func (this *CmsgLens) Type() int32

type IcmpHdr

type IcmpHdr struct {
	Type     uint8
	Code     uint8
	Checksum uint16
	Payload  uint32
}

ICMP v4

func (*IcmpHdr) EchoId

func (icmp *IcmpHdr) EchoId() uint16

func (*IcmpHdr) EchoSeq

func (icmp *IcmpHdr) EchoSeq() uint16

func (*IcmpHdr) Gateway

func (icmp *IcmpHdr) Gateway() uint32

func (*IcmpHdr) Mtu

func (icmp *IcmpHdr) Mtu() uint16

type IcmpV6Hdr

type IcmpV6Hdr struct {
	Type     uint8
	Code     uint8
	Checksum uint16
	Payload  uint32
}

ICMP v6

func (*IcmpV6Hdr) EchoId

func (icmp *IcmpV6Hdr) EchoId() uint16

func (*IcmpV6Hdr) EchoSeq

func (icmp *IcmpV6Hdr) EchoSeq() uint16

func (*IcmpV6Hdr) Mtu

func (icmp *IcmpV6Hdr) Mtu() uint32

type MMsghdr

type MMsghdr struct {
	syscall.Msghdr         // what to send
	NTransferred   uint32  // returns number of bytes actually sent/received
	Pad_cgo_2      [4]byte // alignment
}

must match layout of C struct mmsghdr

func (*MMsghdr) Prep

func (hdr *MMsghdr) Prep(iov *syscall.Iovec, iovlen int)

prep for sending/receiving data

type ManagedFd

type ManagedFd uint64

Manages a socket file descriptor (fd)

When a goroutine is using an fd, it may be blocked on it. When it is time for that goroutine to die, another goroutine will need to tell it. The safe way to do that is to shutdown the fd, which will unblock the goroutine, and then that goroutine can close the fd.

This allows that activity to be safely performed.

On Linux, fds are limited to 32 bits (see epoll interfaces). OS limits push that limit down quite a bit more.

NOTES:

  • When a TCP socket is shutdown, reads will return 0 bytes, so the reader needs to check IsDisabled upon getting 0 bytes.

  • When a TCP listen socket is shutdown, the goroutine waiting for connections will get an error (in the accept). IsDisabled should be checked.

  • When a UDP socket is shutdown, recvmmsg will return 1 message, but the first message will be 0 bytes. IsDisabled needs to be checked in this case.

States

                Set           Disable
-----> [empty] -----> [open] --------> [open,shutdown,disabled]
         |  ^           |                  |
         |  |   Close   |                  | Close
         |  +-----------+                  |
         |                                 |
         |      Disable                    v
         +---------------------------> [disabled]

func (*ManagedFd) Acquire

func (this *ManagedFd) Acquire() (fd int, valid bool)

add a reference count to this if it is valid, returning fd if valid

func (*ManagedFd) Clear

func (this *ManagedFd) Clear()

dangerously clear all state - only use when you are *sure*

func (*ManagedFd) Close

func (this *ManagedFd) Close() (closed bool, err error)

If the fd is open, close it. Preserve disabled state. If fd is not disabled, Set can be used to set the fd to a new value.

func (*ManagedFd) Disable

func (this *ManagedFd) Disable() (shutdown bool)

disable the fd, returning true if this caused a shutdown

this is commonly used when a goroutine may be blocking on an fd, and another goroutine is trying to tell it that it is time to die. this provides that notification to the blocked goroutine, but keeps the fd open. this prevents the race condition where one goroutine closes a fd, and then a new connection is made that gets the same fd, and then the other goroutine that was using the fd now has an fd to the wrong thing

func (*ManagedFd) Eject

func (this *ManagedFd) Eject() (fd int, ok bool)

If the fd is open, eject it. Preserve disabled state. Clear the open bit.

func (*ManagedFd) From

func (this *ManagedFd) From(from *ManagedFd) (ok bool)

Transfer state from other ManagedFd to this

On success, from will be cleared and this will contain the state.

On failure, both this and from will remain unchanged.

Failure is caused when this already has state.

func (*ManagedFd) Get

func (this *ManagedFd) Get() (fd int, valid bool)

get the currently set fd and whether it is valid (open and not disabled)

func (*ManagedFd) GetStatus

func (this *ManagedFd) GetStatus() (open, disabled bool, count int)

Get current status - is fd open? - is fd disabled? - current ref count

func (*ManagedFd) IsClosed

func (this *ManagedFd) IsClosed() (closed bool)

func (*ManagedFd) IsDisabled

func (this *ManagedFd) IsDisabled() (disabled bool)

func (*ManagedFd) IsDisabledOrClosed

func (this *ManagedFd) IsDisabledOrClosed() (disabledOrClosed bool)

func (*ManagedFd) IsSet

func (this *ManagedFd) IsSet() bool

disabled or open or previously used

func (*ManagedFd) Release

func (this *ManagedFd) Release() (open, disabled bool, count int)

remove a reference count to this, returning status and remaining refs

func (*ManagedFd) ReleaseAndDisableAndMaybeClose

func (this *ManagedFd) ReleaseAndDisableAndMaybeClose() (count int)

remove a ref to this, disabling if not disabled, closing if count zero

func (*ManagedFd) Set

func (this *ManagedFd) Set(fd int) (actuallySet bool)

set the file descriptor to be managed.

this will return false if the ManagedFd is disabled or already set

func (*ManagedFd) ShutdownRead

func (this *ManagedFd) ShutdownRead() (valid bool)

shut down the read portion of the socket if it is valid.

this is commonly used when a goroutine may be blocking on an fd, and another goroutine is trying to tell it that it is time to die. this provides that notification to the blocked goroutine, but keeps the fd open. this prevents the race condition where one goroutine closes a fd, and then a new connection is made that gets the same fd, and then the other goroutine that was using the fd now has an fd to the wrong thing

type MtuDisco

type MtuDisco int

MTU Discovery option

https://man7.org/linux/man-pages/man7/ip.7.html

/usr/include/bits/in.h

const (
	MtuDiscoNone  MtuDisco = 0 // unset (leave as system default)
	MtuDiscoDo    MtuDisco = 1 // always set DF
	MtuDiscoDont  MtuDisco = 2 // do not set DF
	MtuDiscoProbe MtuDisco = 3 // set DF, ignore path MTU
	MtuDiscoWant  MtuDisco = 4 // fragment according to path MTU, or set DF
	MtuDiscoIntfc MtuDisco = 5 // always use intfc MTU, do not set DF, ignore icmp
	MtuDiscoOmit  MtuDisco = 6 // Like MtuDiscoIntfc, but all pkts to be fragmented
)

type MtuEchoer

type MtuEchoer struct {

	//
	// if set, log output
	//
	Name string

	//
	// if set, called on receipt of each pkt
	//
	OnPacket func(pkt []byte, from syscall.Sockaddr) (err error)
	// contains filtered or unexported fields
}

MTU discovery server - echos back pkts sent by MtuProber client

func (*MtuEchoer) Close

func (this *MtuEchoer) Close()

func (*MtuEchoer) Echo

func (this *MtuEchoer) Echo(timeout time.Duration) (err error)

echo datagrams for the duration, or forever if timeout not positive

func (*MtuEchoer) NewSock

func (this *MtuEchoer) NewSock(near Address) (err error)

add a UDP socket, suitable for use to discover MTU

func (*MtuEchoer) SetSock

func (this *MtuEchoer) SetSock(sock *Socket)

sock should be connected, constructed similarly as per NewSock

type MtuProber

type MtuProber struct {

	//
	// if set, log output
	//
	Name string

	//
	// if set, interval between sending probes.  Default 120ms
	//
	ProbeInterval time.Duration

	//
	// set this to create initial buffer, or one will be created w/o your help
	//
	OnStart func(size uint16) (space []byte)

	//
	// if set, is called to create pkt from space prior to each send.
	//
	// size is how many bytes pkt should be in length
	//
	BeforeSend func(size uint16, space []byte) (pkt []byte, err error)

	//
	// if set, is called after receiving each pkt
	//
	AfterRecv func(pkt []byte) (err error)

	//
	// if set, set smallest probe size.  otherwise, smallest compliant will be used
	//
	MtuMin uint16

	//
	// if set, set largest probe size.  otherwise, reasonable max will be used
	//
	MtuMax uint16

	//
	// Result: if non-zero, kernel cached PMTU value
	//
	CachedPmtu uint16

	//
	// Result: detected/probed PMTU value
	//
	Pmtu uint16

	//
	// Result: overhead of IP and UDP
	//
	Overhead uint16

	//
	// Result: if BeforeSend and AfterRecv not set, this is computed
	//
	LatencyAvg time.Duration
	LatencyMin time.Duration
	LatencyMax time.Duration
	// contains filtered or unexported fields
}

client side of MTU discovery - sends UDP probes and sees what happens

func (*MtuProber) Close

func (this *MtuProber) Close()

func (*MtuProber) NewCheckSock

func (this *MtuProber) NewCheckSock(src, dst Address) (err error)

Create a new socket to be the check socket, used to query kernel pmtu table. If not set, then the probe socket will be used.

func (*MtuProber) NewProbeSock

func (this *MtuProber) NewProbeSock(src, dst Address) (err error)

create a new socket to be the probe socket, used to send/recv probes.

func (*MtuProber) Probe

func (this *MtuProber) Probe() (pmtu uint16, err error)

perform probing until PMTU is known

func (*MtuProber) SetCheckSock

func (this *MtuProber) SetCheckSock(sock *Socket)

set external socket to be used to query kernel pmtu must be constructed similarly to NewProbeSock sock.FarAddr must be set

func (*MtuProber) SetProbeSock

func (this *MtuProber) SetProbeSock(sock *Socket)

set external socket to be used to send/recv probes sock should be connected, constructed similarly as per NewSock

type Polled

type Polled struct {
	NearAddr Address // optional - use as lookup for OnInput
	Sock     *Socket

	//
	// if set, call when socket hangup
	//
	OnHup func(p *Polled) (ok bool, err error)

	//
	// if set, call when input is ready on socket
	//
	OnInput func(p *Polled) (ok bool, err error)

	//
	// if set, call when error queue is ready on socket
	//
	OnErrorQ func(p *Polled) (ok bool, err error)
	// contains filtered or unexported fields
}

type Poller

type Poller struct {
	// contains filtered or unexported fields
}

allows polling a socket for activity

func (*Poller) Add

func (this *Poller) Add(polled *Polled) (err error)

func (*Poller) AddControlPipe

func (this *Poller) AddControlPipe(onCntl func() (bool, error)) (err error)

if other threads need to tell this thread (the one running Poller) things, then use this to add a control pipe to activate your supplied callback

func (*Poller) Close

func (this *Poller) Close()

must be called by thread running Poller to cause close from another thread, send a cntl message

func (*Poller) IsStarted

func (this *Poller) IsStarted() bool

func (*Poller) NudgeControl

func (this *Poller) NudgeControl() (err error)

if other threads need to tell the thread running Poller things send a nudge. the actual message should be in a chan or something.

func (*Poller) Open

func (this *Poller) Open() (err error)

func (*Poller) Poll

func (this *Poller) Poll(millis int) (ok bool, err error)

Poll, waiting up to millis (-1 if forever) for input Returning false if a callback returned false

func (*Poller) PollFor

func (this *Poller) PollFor(timeout time.Duration) (ok bool, err error)

Poll for duration Returning false if callback returned false

func (*Poller) PollForever

func (this *Poller) PollForever() (ok bool, err error)

Poll forever (or until stopped) Returning false if callback returned false

func (*Poller) Remove

func (this *Poller) Remove(polled *Polled) (err error)

type SockOpt

type SockOpt func(s *Socket) (err error)

type Socket

type Socket struct {
	Fd       ManagedFd
	FarAddr  syscall.Sockaddr
	NearAddr syscall.Sockaddr
	Error    error
	// contains filtered or unexported fields
}

Enable reasonable access to the Berkeley socket API.

needed when golang does not allow in high level interface, or for things like setting socket options before bind.

implements net.Conn, io.Closer, io.Reader, io.Writer

sock, err := NewSocket().
    ResolveFarAddr(host, port).
    ConstructTcp().
    SetTimeout(7*time.Second).
    Connect().
    Done()

func NewSocket

func NewSocket() *Socket

func (*Socket) Accept

func (this *Socket) Accept(sock *Socket) (err error)

accept a connection, storing the fd and addresses in sock

func (*Socket) Bind

func (this *Socket) Bind(unless ...bool) *Socket

see https://idea.popcount.org/2014-04-03-bind-before-connect/

func (*Socket) BindTo

func (this *Socket) BindTo(host string, port int, unless ...bool) *Socket

func (*Socket) CancelDeadline

func (this *Socket) CancelDeadline()

func (*Socket) ClearTimeout

func (this *Socket) ClearTimeout() *Socket

func (this *Socket) ClearTimeout(timeout time.Duration) *Socket {

func (*Socket) Close

func (this *Socket) Close() error

preserves disabled state

func (*Socket) Connect

func (this *Socket) Connect(unless ...bool) *Socket

func (*Socket) Construct

func (this *Socket) Construct(sockType, proto int) *Socket

func (*Socket) ConstructFd

func (this *Socket) ConstructFd(mfd *ManagedFd) *Socket

construct Socket from provided mfd, transferring state from mfd to this.

if transfer of state fails, then fd will be closed

func (*Socket) ConstructTcp

func (this *Socket) ConstructTcp() *Socket

func (*Socket) ConstructUdp

func (this *Socket) ConstructUdp() *Socket

func (*Socket) Disable

func (this *Socket) Disable()

shutdown

func (*Socket) Done

func (this *Socket) Done() (s *Socket, err error)

end chain, clean up, return any error

func (*Socket) GetFarAddress

func (this *Socket) GetFarAddress(rv *Address) *Socket

func (*Socket) GetNearAddress

func (this *Socket) GetNearAddress(rv *Address) *Socket

func (*Socket) GetOptInt

func (this *Socket) GetOptInt(layer, key int, value *int) *Socket

func (*Socket) GetOptMtu

func (this *Socket) GetOptMtu(mtu *int, unless ...bool) *Socket

If socket is connected, can get the MTU with this, which will either be the MTU of the interface, or the path MTU (PMTU) discovered from ICMP and cached in the kernel.

Especially handy after EMSGSIZE.

func (*Socket) GetOptRcvBuf

func (this *Socket) GetOptRcvBuf(size *int) *Socket

func (*Socket) GetOptSndBuf

func (this *Socket) GetOptSndBuf(size *int) *Socket

func (*Socket) GetPeerName

func (this *Socket) GetPeerName(unless ...bool) *Socket

func (*Socket) GetSockName

func (this *Socket) GetSockName(unless ...bool) *Socket

func (*Socket) GiveMeTheFreakingFd

func (this *Socket) GiveMeTheFreakingFd(pfd *int) *Socket

really just for test situations

func (*Socket) IpOverhead

func (this *Socket) IpOverhead() (rv int)

func (*Socket) IsDisabled

func (this *Socket) IsDisabled() bool

func (*Socket) IsIpv6

func (this *Socket) IsIpv6() bool

func (*Socket) Listen

func (this *Socket) Listen(depth int, unless ...bool) *Socket

func (*Socket) LocalAddr

func (this *Socket) LocalAddr() net.Addr

func (*Socket) Log

func (this *Socket) Log(msg string, args ...any) *Socket

func (*Socket) ManageFd

func (this *Socket) ManageFd(managed *ManagedFd) *Socket

safely transfer the internal fd to managed, if managed not nil or already set

func (*Socket) Read

func (this *Socket) Read(buff []byte) (nread int, err error)

func (*Socket) RecvFrom

func (this *Socket) RecvFrom(
	buff []byte, flags int,
) (
	nread int, from syscall.Sockaddr, err error,
)

wrapper for go syscall, which require alloc of from on each recv useful for simple, non-performant cases

func (*Socket) RecvMsg

func (this *Socket) RecvMsg(
	msghdr *syscall.Msghdr,
	flags int,
) (
	nread int, err error,
)

func (*Socket) RemoteAddr

func (this *Socket) RemoteAddr() net.Addr

func (*Socket) Reset

func (this *Socket) Reset() *Socket

be careful! if Fd holds a live fd, it may be lost!

func (*Socket) ResolveFarAddr

func (this *Socket) ResolveFarAddr(host string, port int, unless ...bool) *Socket

func (*Socket) ResolveNearAddr

func (this *Socket) ResolveNearAddr(host string, port int, unless ...bool) *Socket

func (*Socket) Send

func (this *Socket) Send(buff []byte, flags int) (err error)

func (*Socket) SendMsg

func (this *Socket) SendMsg(
	msghdr *syscall.Msghdr, flags int,
) (
	nsent int, err error,
)

func (*Socket) SendTo

func (this *Socket) SendTo(
	buff []byte, flags int, to syscall.Sockaddr,
) (
	err error,
)

func (*Socket) SetDeadline

func (this *Socket) SetDeadline(t time.Time) error

set a zero deadline to cancel deadline

func (*Socket) SetFarAddr

func (this *Socket) SetFarAddr(far syscall.Sockaddr, unless ...bool) *Socket

func (*Socket) SetFarAddress

func (this *Socket) SetFarAddress(far Address, unless ...bool) *Socket

func (*Socket) SetFarIpPort

func (this *Socket) SetFarIpPort(ip net.IP, port int, unless ...bool) *Socket

func (*Socket) SetNearAddr

func (this *Socket) SetNearAddr(near syscall.Sockaddr, unless ...bool) *Socket

func (*Socket) SetNearAddress

func (this *Socket) SetNearAddress(near Address, unless ...bool) *Socket

if near is not set, then will be set to 0.0.0.0:0

func (*Socket) SetNearIpPort

func (this *Socket) SetNearIpPort(ip net.IP, port int, unless ...bool) *Socket

func (*Socket) SetOpt

func (this *Socket) SetOpt(opt SockOpt, unless ...bool) *Socket

func (*Socket) SetOptDscpTos

func (this *Socket) SetOptDscpTos(tos byte, unless ...bool) *Socket

set IP DSCP / TOS (priority) bits.

func (*Socket) SetOptGso

func (this *Socket) SetOptGso(size int, unless ...bool) *Socket

About GSO (generic segment offload):

https://blog.cloudflare.com/accelerating-udp-packet-transmission-for-quic/

kernel 4.18+ is required.

We have not tested with kernel 4.x, but have tested with 5.4+.

This feature can be controlled using the UDP_SEGMENT socket option:

setsockopt(fd, SOL_UDP, UDP_SEGMENT, &gso_size, sizeof(gso_size)))

As well as via ancillary data, to control segmentation for each sendmsg() call:

cm = CMSG_FIRSTHDR(&msg);
cm->cmsg_level = SOL_UDP;
cm->cmsg_type = UDP_SEGMENT;
cm->cmsg_len = CMSG_LEN(sizeof(uint15_t));
*((uint15_t *) CMSG_DATA(cm)) = gso_size;

Where gso_size is the size of each segment that form the "super buffer" passed to the kernel from the application. Once configured, the application can provide one contiguous large buffer containing a number of packets of gso_size length (as well as a final smaller packet), that will then be segmented by the kernel (or the NIC if hardware segmentation offloading is supported and enabled).

func (*Socket) SetOptInt

func (this *Socket) SetOptInt(layer, key, value int, unless ...bool) *Socket

func (*Socket) SetOptKeepalive

func (this *Socket) SetOptKeepalive(tristate ...int) *Socket

default to 'on'. if specified, values are 0 (off), 1 (on) - any other value is 'no change'

func (*Socket) SetOptMtuDiscover

func (this *Socket) SetOptMtuDiscover(disco MtuDisco, unless ...bool) *Socket

func (*Socket) SetOptNoDelay

func (this *Socket) SetOptNoDelay(tristate ...int) *Socket

turn off/on Nagle algorithm (OS usually has this on by default) default to 'on'. if specified, values are 0 (off), 1 (on) - any other value is 'no change'

func (*Socket) SetOptRcvBuf

func (this *Socket) SetOptRcvBuf(size int, unless ...bool) *Socket

func (*Socket) SetOptRcvTimeout

func (this *Socket) SetOptRcvTimeout(timeout time.Duration, unless ...bool) *Socket

set SO_RCVTIMEO on socket if timeout is positive

func (*Socket) SetOptRecvPktInfo

func (this *Socket) SetOptRecvPktInfo(tristate ...int) *Socket

for recvmsg/recvmmsg, allow receipt of cmsghdr

default to 'on'. if specified, values are 0 (off), 1 (on) - any other value is 'no change'

func (*Socket) SetOptReuseAddr

func (this *Socket) SetOptReuseAddr(tristate ...int) *Socket

must be before bind

default to 'on'. if specified, values are 0 (off), 1 (on) - any other value is 'no change'

see https://idea.popcount.org/2014-04-03-bind-before-connect/

func (*Socket) SetOptReusePort

func (this *Socket) SetOptReusePort(tristate ...int) *Socket

must be before bind

default to 'on'. if specified, values are 0 (off), 1 (on) - any other value is 'no change'

func (*Socket) SetOptSndBuf

func (this *Socket) SetOptSndBuf(size int, unless ...bool) *Socket

func (*Socket) SetOptSndTimeout

func (this *Socket) SetOptSndTimeout(timeout time.Duration, unless ...bool) *Socket

set SO_SNDTIMEO on socket if timeout is positive

func (*Socket) SetOptTristate

func (this *Socket) SetOptTristate(layer, key int, tristate []int) *Socket

func (*Socket) SetReadDeadline

func (this *Socket) SetReadDeadline(t time.Time) error

func (*Socket) SetTimeout

func (this *Socket) SetTimeout(timeout time.Duration) *Socket

func (*Socket) SetWriteDeadline

func (this *Socket) SetWriteDeadline(t time.Time) error

func (*Socket) ShutdownRead

func (this *Socket) ShutdownRead() bool

func (*Socket) Temp

func (this *Socket) Temp(mfd ManagedFd) *Socket

construct a temporary Socket from mfd, not transferring state.

func (*Socket) Then

func (this *Socket) Then(thenF func(*Socket) error) *Socket

perform user specified validation

func (*Socket) Write

func (this *Socket) Write(buff []byte) (nwrote int, err error)

type UdpEndpoint

type UdpEndpoint struct {
	Iov  []syscall.Iovec // must be on heap, so keep here
	Hdrs []MMsghdr       // must be on heap, so keep here
}

enables use of recvmmsg and sendmmsg system calls

func (*UdpEndpoint) IovFiller

func (this *UdpEndpoint) IovFiller(size int) func([]syscall.Iovec)

returns a func that is suitable for use with SetupVector

func (*UdpEndpoint) RecvMMsg

func (this *UdpEndpoint) RecvMMsg(fd int) (messages int, err syscall.Errno)

receive messages from fd

after this call, you will need to: - loop thru the messages and process them - for each message, reset NTranferred back to 0 - (optionally) provide new buffers for the iovs used (if not reusing them)

this code is escape optimized

func (*UdpEndpoint) RecvNamer

func (this *UdpEndpoint) RecvNamer() (name *byte, namelen uint32)

suitable as nameFill parameter for receiving endpoints

func (*UdpEndpoint) SendMMsgRetry

func (this *UdpEndpoint) SendMMsgRetry(fd, n int) (retries int, err syscall.Errno)

send n messages (previously set up in Hdrs) on fd

func (*UdpEndpoint) SendNamer

func (this *UdpEndpoint) SendNamer(
	dst syscall.Sockaddr,
	space []byte,
) (
	rv func() (*byte, uint32),
)

suitable to create function for nameFill parameter of sending endpoints where all packets will go to the same place.

The space param needs to point to heap storage and be at least 28 bytes.

func (*UdpEndpoint) SetupVectors

func (this *UdpEndpoint) SetupVectors(
	messages, iovsPer int,
	iovFill func(iov []syscall.Iovec),
	nameFill func() (name *byte, namelen uint32),
)

setup the initial vectors.

for sending, name should be set. for receiving, name should be nil.

if iovFill is nil, then it is up to you to later do that.

if nameFill is nil, then name and namelen will be left empty. This is a good option for connected datagram sockets.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL