Documentation
¶
Overview ¶
Package utp implements the Micro Transport Protocol (uTP, BEP 29), a reliable, ordered byte stream over UDP with LEDBAT delay-based congestion control, in pure Go.
A Socket runs on one UDP socket (Bind) or any Conn (NewSocket) and carries any number of connections. Connect dials a peer and Accept waits for an incoming connection; both return a Stream, whose Read and Write take a context that governs that call:
sock, err := utp.Bind(ctx, "udp", laddr, nil)
if err != nil {
return err
}
defer sock.Close()
stream, err := sock.Connect(ctx, utp.NewUDPPeer(raddr), utp.NewConnectionConfig())
if err != nil {
return err
}
defer stream.Close()
_, err = stream.Write(ctx, []byte("hello"))
For net.Conn and net.PacketConn, including sharing the UDP port with another protocol such as a DHT, use the utpnet package.
Congestion control ¶
Classic LEDBAT (RFC 6817) is the default. LEDBAT++ and RACK loss detection (RFC 8985) can be selected per connection in ConnectionConfig; both are experimental. See AlgorithmLEDBATPP for LEDBAT++'s known limitation.
Path MTU ¶
Each connection searches for the largest datagram its path carries, starting from ConnectionConfig.MaxPacketSize. Probes are sent with fragmentation disabled where the platform supports it, and ICMP reports can be fed in with Socket.ProcessICMPFragmentation and ProcessICMPError.
Logging ¶
Bind and NewSocket take a *slog.Logger; nil discards logging. Per-packet events are logged at LevelTrace.
Example ¶
package main
import (
"context"
"fmt"
"log"
"net"
"github.com/arxodeus/utp"
)
func main() {
ctx := context.Background()
loopback := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1)}
server, err := utp.Bind(ctx, "udp", loopback, nil)
if err != nil {
log.Fatal(err)
}
defer server.Close()
client, err := utp.Bind(ctx, "udp", loopback, nil)
if err != nil {
log.Fatal(err)
}
defer client.Close()
accepted := make(chan *utp.Stream, 1)
go func() {
stream, err := server.Accept(ctx, nil)
if err != nil {
log.Fatal(err)
}
accepted <- stream
}()
peer := utp.NewUDPPeer(server.LocalAddr().(*net.UDPAddr))
stream, err := client.Connect(ctx, peer, nil)
if err != nil {
log.Fatal(err)
}
if _, err := stream.Write(ctx, []byte("hello")); err != nil {
log.Fatal(err)
}
stream.Close()
var got []byte
in := <-accepted
if _, err := in.ReadToEOF(ctx, &got); err != nil {
log.Fatal(err)
}
in.Close()
fmt.Println(string(got))
}
Output: hello
Index ¶
- Constants
- Variables
- func IsPacket(b []byte) bool
- type CongestionAlgorithm
- type Conn
- type ConnectionConfig
- type ConnectionID
- type ConnectionMetrics
- type ConnectionPeer
- type DontFragmentWriter
- type MetricsObserver
- type PathMTUProvider
- type QueuedReader
- type Socket
- func (s *Socket) Accept(ctx context.Context, config *ConnectionConfig) (*Stream, error)
- func (s *Socket) AcceptBacklog() int
- func (s *Socket) AcceptWithCID(ctx context.Context, cid *ConnectionID, config *ConnectionConfig) (*Stream, error)
- func (s *Socket) Close() error
- func (s *Socket) Connect(ctx context.Context, peer ConnectionPeer, config *ConnectionConfig) (*Stream, error)
- func (s *Socket) ConnectWithCID(ctx context.Context, cid *ConnectionID, config *ConnectionConfig) (*Stream, error)
- func (s *Socket) ConnectionsRefusedAtCapacity() uint64
- func (s *Socket) ConnectionsRefusedByFirewall() uint64
- func (s *Socket) ConnectionsRefusedIDInUse() uint64
- func (s *Socket) LocalAddr() net.Addr
- func (s *Socket) NumConnections() int
- func (s *Socket) PacketsDroppedFullConnQueue() uint64
- func (s *Socket) PacketsResetSent() uint64
- func (s *Socket) ProcessICMPError(quoted []byte, peer ConnectionPeer) bool
- func (s *Socket) ProcessICMPFragmentation(quoted []byte, peer ConnectionPeer, nextHopMTU uint16) bool
- type SocketOption
- type Stream
- func (s *Stream) CID() *ConnectionID
- func (s *Stream) Close() error
- func (s *Stream) CloseRead() error
- func (s *Stream) CloseWrite() error
- func (s *Stream) Done() <-chan struct{}
- func (s *Stream) Read(ctx context.Context, buf []byte) (int, error)
- func (s *Stream) ReadToEOF(ctx context.Context, buf *[]byte) (int, error)
- func (s *Stream) SetWindowSize(bytes uint32)
- func (s *Stream) WindowSize() uint32
- func (s *Stream) Write(ctx context.Context, buf []byte) (int, error)
- func (s *Stream) WriteV(ctx context.Context, bufs [][]byte) (int, error)
- type UDPPeer
Examples ¶
Constants ¶
const DefaultBufferSize = 1024 * 1024
DefaultBufferSize is the default size of each connection's send and receive buffers, in bytes.
const DefaultMaxConnections = 3000
DefaultMaxConnections is the default limit on connections a socket holds before it refuses new incoming ones.
const DefaultMaxIdleTimeout = time.Duration(0)
DefaultMaxIdleTimeout is zero: by default a connection is never closed for silence. See ConnectionConfig.MaxIdleTimeout.
const DefaultMetricsInterval = 10 * time.Millisecond
DefaultMetricsInterval is how often metrics are sampled when an observer is set but no interval is given.
const DefaultSocketBufferSize = 4 * 1024 * 1024
DefaultSocketBufferSize is the size requested for the underlying UDP socket's send and receive buffers. A single goroutine drains the socket, and datagrams the kernel drops before it does are loss uTP must recover from; the operating system's default is too small for a few hundred concurrent connections. The kernel clamps the request to its configured maximum.
const DefaultWindowSize = 1024 * 1024
DefaultWindowSize is the default upper bound on the congestion window, in bytes.
const LevelTrace = slog.Level(-8)
LevelTrace is the level of the package's per-packet logging, one step below slog.LevelDebug. A handler enabled for it sees every packet sent and received.
Variables ¶
var ( // ErrReset means the peer reset the connection. ErrReset = errors.New("utp: connection reset by peer") // ErrTimedOut means the connection was abandoned after repeated // retransmission timeouts, the handshake was not answered, or the idle // timeout expired. ErrTimedOut = errors.New("utp: connection timed out") // ErrConnRefused means an ICMP error arrived for a connection that had // only sent its SYN, so nothing is listening. Otherwise an ICMP error, // like a received ST_RESET, produces ErrReset. ErrConnRefused = errors.New("utp: connection refused") )
var ( // ErrNotConnected is returned by Write after CloseWrite or Close, and // for a connection that ended without an error of its own. ErrNotConnected = errors.New("utp: not connected") // ErrReadClosed is returned by Read after CloseRead. The connection is // still alive and may still send; this end has stopped taking delivery. ErrReadClosed = errors.New("utp: read side closed") // ErrSocketClosed is reported by a connection whose socket has been // closed. It wraps net.ErrClosed. ErrSocketClosed = fmt.Errorf("utp: socket closed: %w", net.ErrClosed) )
var ( // ErrAcceptTimedOut is returned by AcceptWithCID when no matching SYN // arrives within 20 seconds. ErrAcceptTimedOut = errors.New("utp: timed out waiting for incoming connection") )
var ErrDontFragmentUnsupported = errors.New("utp: per-packet don't-fragment is not supported on this platform")
ErrDontFragmentUnsupported is returned by WriteToDontFragment when fragmentation cannot be disabled for a single datagram on this platform. Nothing has been sent.
Functions ¶
func IsPacket ¶
IsPacket reports whether b looks like a uTP packet, as far as its header can tell: its length, packet type, version and first extension type. A datagram it accepts is one the socket can parse, and one it rejects is one the socket would drop. utpnet uses it to tell uTP from other protocols sharing the port.
Types ¶
type CongestionAlgorithm ¶
type CongestionAlgorithm int
CongestionAlgorithm selects which congestion controller a connection runs.
const ( // AlgorithmLEDBAT is classic LEDBAT (RFC 6817), the default. AlgorithmLEDBAT CongestionAlgorithm = iota // AlgorithmLEDBATPP is LEDBAT++. Experimental: a LEDBAT++ flow that // joins a link another LEDBAT++ flow already fills takes about 70% of // it while both run, rather than an even share. AlgorithmLEDBATPP )
func (CongestionAlgorithm) String ¶
func (a CongestionAlgorithm) String() string
String returns the algorithm's name.
type Conn ¶
type Conn interface {
// ReadFrom reads one datagram into b and returns its length and sender.
ReadFrom(b []byte) (int, ConnectionPeer, error)
// WriteTo sends b as one datagram to dst.
WriteTo(b []byte, dst ConnectionPeer) (int, error)
// Close closes the transport, ending a ReadFrom in progress.
Close() error
}
Conn is the datagram transport a Socket runs over.
WriteTo must behave like a UDP socket's: it may wait for the local send path, but never for the peer to read. The socket writes from the goroutine that reads, so a WriteTo that waited for the other side to read could deadlock two sockets. A transport that cannot keep up drops, as UDP does. WriteTo is called concurrently.
WriteTo must not retain b after it returns: the socket reuses the buffer. net.PacketConn already works this way; a transport that queues datagrams must copy them.
A Conn may also have the methods
HoldPeer(peer ConnectionPeer) ReleasePeer(peer ConnectionPeer)
The socket then calls HoldPeer when it starts a connection with peer, as it sends or receives a SYN, and ReleasePeer when it forgets that connection. A transport that keeps per-peer state, such as the original address to reply to, keeps it while held: from the first handshake packet to the last packet of the close. Each HoldPeer is matched by one ReleasePeer. They are called with the socket's connection table locked and must not call back into the socket.
type ConnectionConfig ¶
type ConnectionConfig struct {
// MaxPacketSize is the largest datagram the connection sends, in bytes:
// the ceiling of its path-MTU search.
MaxPacketSize uint16
// MaxConnAttempts is how many times the SYN is sent before a dial gives
// up with ErrTimedOut.
MaxConnAttempts int
// MaxIdleTimeout closes the connection with ErrTimedOut once nothing has
// been received and nothing written for this long. Zero, the default,
// disables it: a connection whose peer vanished while nothing was in
// flight stays open until the application closes it, and one
// interrupted by an outage resumes when the path returns. A live peer
// sends a keep-alive every 29 seconds, so a value well above that never
// closes a live connection.
MaxIdleTimeout time.Duration
// InitialTimeout is the retransmission timeout before the first
// round-trip sample, and the SYN's first timeout.
InitialTimeout time.Duration
// MinTimeout is the floor of the retransmission timeout.
MinTimeout time.Duration
// MaxTimeout caps the retransmission timeout and its backoff. Zero, the
// default, means no cap.
MaxTimeout time.Duration
// TargetDelay is the queuing delay classic LEDBAT aims for.
TargetDelay time.Duration
// DelayWindow is how far back the congestion controller looks for its
// base delay: the lowest one-way delay seen, taken as the delay of an
// empty queue. The window is kept in thirteen buckets; the default is
// thirteen minutes. See baseDelayHist.
//
// The window bounds the error clock drift causes: a sender whose clock
// runs slow sees its measured delay grow until inflated samples age out,
// so the steady-state error is the window times the drift rate.
DelayWindow time.Duration
// WindowSize is the upper bound on the congestion window, in bytes.
WindowSize uint32
// BufferSize is the size of the send and receive buffers, in bytes. The
// receive window advertised to the peer is at most this.
BufferSize int
// Metrics, when set, receives periodic snapshots of this connection.
// See MetricsObserver for the constraints on the callback.
Metrics MetricsObserver
// MetricsInterval is the minimum gap between snapshots. Defaults to
// DefaultMetricsInterval.
MetricsInterval time.Duration
// KeepAliveInterval is how long an established connection may stay
// silent before sending a keep-alive. The default of 29 seconds is below
// the 30-second UDP mapping timeout common in NATs.
KeepAliveInterval time.Duration
// ZeroWindowProbeInterval is how long a zero receive window from the
// peer is tolerated before one packet is sent to elicit a window update.
// The peer's update when it reopens the window is a single packet; if it
// is lost, the sender would otherwise have nothing outstanding and no
// reason to transmit. The default is 15 seconds.
ZeroWindowProbeInterval time.Duration
// CongestionAlgorithm selects the congestion controller. The zero value
// is AlgorithmLEDBAT; AlgorithmLEDBATPP selects LEDBAT++, which is
// experimental.
CongestionAlgorithm CongestionAlgorithm
// RACK replaces the default loss detection, under which a packet is lost
// once three packets sent after it are acknowledged, with the
// time-based rule of RFC 8985. Off by default. Experimental.
RACK bool
// NoDelay sends a partial packet as soon as the window allows, like
// TCP_NODELAY. By default a packet smaller than the maximum waits while
// anything else is unacknowledged, and later writes are appended to it
// until it is full, everything before it is acknowledged, or the write
// side closes. NoDelay lowers latency for small writes at the cost of
// more, smaller packets.
NoDelay bool
// contains filtered or unexported fields
}
ConnectionConfig configures a connection. Start from NewConnectionConfig, which sets the defaults, and change what is needed. A config may be shared by several connections, but must not be modified once in use.
func NewConnectionConfig ¶
func NewConnectionConfig() *ConnectionConfig
NewConnectionConfig returns a config with the default settings.
type ConnectionID ¶
type ConnectionID struct {
// Send is the id this end sends with: the peer's receive id.
Send uint16
// Recv is the id this end receives on.
Recv uint16
// Peer is the remote end.
Peer ConnectionPeer
// contains filtered or unexported fields
}
ConnectionID identifies a connection by its send and receive ids and its peer.
func NewConnectionID ¶
func NewConnectionID(peer ConnectionPeer, recvID uint16, sendID uint16) *ConnectionID
NewConnectionID returns the connection id for peer with the given receive and send ids.
func (*ConnectionID) Hash ¶
func (id *ConnectionID) Hash() string
Hash returns the key the connection is tracked under. NewConnectionID caches it; for a ConnectionID built as a struct literal it is computed on each call.
func (*ConnectionID) String ¶
func (id *ConnectionID) String() string
String returns a description of the id for logging.
type ConnectionMetrics ¶
type ConnectionMetrics struct {
// At is when the snapshot was taken.
At time.Time
// CID identifies the connection.
CID *ConnectionID
// CwndBytes is the congestion window: what the controller believes the
// path will carry.
CwndBytes uint32
// InFlightBytes is the volume the controller considers outstanding.
InFlightBytes uint32
// MinCwndBytes is the floor the window will not drop below. A controller
// pinned here has collapsed.
MinCwndBytes uint32
// PeerRecvWindow is the peer's advertised receive window. When this is
// smaller than CwndBytes, flow control -- not congestion control -- is
// what limits sending.
PeerRecvWindow uint32
// RTT is the smoothed round-trip estimate, in whole milliseconds.
RTT time.Duration
// FineRTT is the same estimate kept in microseconds, for measuring a
// queue a millisecond or two deep.
FineRTT time.Duration
// RTTVarianceMicros is the RTT variance estimate, in microseconds.
RTTVarianceMicros int64
// Timeout is the current retransmission timeout.
Timeout time.Duration
// BaseDelay is the lowest one-way delay seen in the delay window:
// LEDBAT's estimate of the path with an empty queue. CurrentDelay is the
// newest sample of the same series.
//
// Both measure the outbound path, as reported by the peer in the
// timestamp_difference field; that is the direction LEDBAT controls.
// PeerTimestampDiff measures the inbound path.
BaseDelay time.Duration
CurrentDelay time.Duration
// ClockSkewCorrection is how much has been added to BaseDelay to cancel
// clock drift between the two ends, detected from the peer's own base
// delay falling. Zero on a pair of clocks running at the same rate.
ClockSkewCorrection time.Duration
// ClockDrift is the estimated slope of the delay the peer reports for
// our packets, in microseconds per five-second slot, smoothed 7:1
// towards its history. A negative value means the reported delay is
// falling, as when the peer's clock runs slow; below -200000 it incurs
// a penalty (ClockDriftPenalty).
//
// ClockSkewCorrection corrects for ordinary drift between honest
// clocks; ClockDrift detects drift far outside what hardware produces.
ClockDrift int64
// ClockDriftPenalty is how much is currently added to the measured
// queuing delay because of ClockDrift. It is zero on any ordinary path.
ClockDriftPenalty time.Duration
// MtuCurrent is the datagram size the path-MTU search is currently
// sending, and MtuFloor and MtuCeiling bound the sizes it has yet to
// test. A converged search has all three equal.
MtuCurrent uint32
MtuFloor uint32
MtuCeiling uint32
// MtuProbesLostToDuplicateAcks counts probes that duplicate
// acknowledgements showed were too large for the path.
MtuProbesLostToDuplicateAcks uint64
// WindowReopenedAcks counts acknowledgements sent because delivering
// data to the application opened a receive window larger than the one
// last advertised. It is zero while the reader keeps up, since the
// acknowledgement for incoming data already carries a current window.
WindowReopenedAcks uint64
// PeerTimestampDiff is the one-way delay measured from the peer's timestamps:
// how long the peer's last packet took to arrive. It is echoed back in
// timestamp_difference_microseconds. It measures the inbound path,
// whereas BaseDelay and CurrentDelay measure the outbound one.
PeerTimestampDiff time.Duration
// TargetDelayMicros is the standing queue the controller aims for.
TargetDelayMicros uint32
// SlowStart reports whether the controller is still in slow start.
SlowStart bool
// AppLimitedSince is how long since the sender last had data to send
// and no window to send it in. After a second the controller stops
// growing the window, since an unfilled window measures nothing. Zero
// means the window has never been filled.
AppLimitedSince time.Duration
// PacketsSent and BytesSent count every transmission, retransmissions
// included.
PacketsSent uint64
BytesSent uint64
// PacketsRetransmitted and BytesRetransmitted count only retransmissions.
// The ratio to PacketsSent is the retransmit rate.
PacketsRetransmitted uint64
BytesRetransmitted uint64
// PacketsReceived and BytesReceived count packets accepted from the peer.
PacketsReceived uint64
BytesReceived uint64
// Timeouts counts retransmission-timeout events.
Timeouts uint64
// FastRetransmits counts packets resent because they were declared lost
// by duplicate acks rather than by a timeout.
FastRetransmits uint64
// LossProbes counts packets resent by the loss probe because nothing had
// been acknowledged for a probe timeout, shorter than the retransmission
// timeout.
LossProbes uint64
// RackLosses counts packets declared lost by RACK loss detection, and
// RackRelosts those that were already retransmissions. Both are zero
// with RACK off.
RackLosses uint64
RackRelosts uint64
// SendBufferPending is unsent application data still buffered.
SendBufferPending int
// RecvBufferPending is received data not yet read by the application,
// contiguous or held behind a gap.
RecvBufferPending int
// RecvBufferReadable is the contiguous part of RecvBufferPending, which
// can be delivered now. The difference is data held behind a gap; a
// large difference indicates a receiver waiting on a missing packet
// rather than a slow reader.
RecvBufferReadable int
// RecvBufferDrops counts data packets refused because the receive
// buffer had no room. Each is a gap the peer must fill by
// retransmission.
RecvBufferDrops uint64
// PendingWrites is the number of queued write requests.
PendingWrites int
// State is the connection's state: "connecting", "connected" or "closed".
State string
}
ConnectionMetrics is a snapshot of one connection's state.
func (ConnectionMetrics) QueueingDelay ¶
func (m ConnectionMetrics) QueueingDelay() time.Duration
QueueingDelay estimates the standing queue on the outbound path: the current one-way delay minus the lowest seen. This is the quantity LEDBAT bounds. It returns zero until BaseDelay has been established.
func (ConnectionMetrics) RetransmitRate ¶
func (m ConnectionMetrics) RetransmitRate() float64
RetransmitRate is the fraction of transmissions that were retransmissions.
type ConnectionPeer ¶
type ConnectionPeer interface {
// Hash returns the peer's key, conventionally its address as text.
Hash() string
}
ConnectionPeer identifies the remote end of a connection. Hash must return a stable string that distinguishes peers.
type DontFragmentWriter ¶
type DontFragmentWriter interface {
WriteToDontFragment(b []byte, dst ConnectionPeer) (int, error)
}
DontFragmentWriter is an optional interface for a Conn that can send a single datagram with fragmentation disabled. The socket uses it for path-MTU probes: a probe too large for the path is then dropped rather than fragmented, so the search learns the size the path actually carries.
A Conn that cannot disable fragmentation at the moment returns ErrDontFragmentUnsupported without sending, and the socket sends the datagram normally.
type MetricsObserver ¶
type MetricsObserver func(ConnectionMetrics)
MetricsObserver receives connection snapshots.
It is called with the connection's lock held, from whichever goroutine is running the connection: its event loop, or the socket's reader. It must not block and must not call into the stream or socket: blocking stalls every connection on the socket, and calling back can deadlock. Copy what is needed and return.
type PathMTUProvider ¶
type PathMTUProvider interface {
PathMTU(peer ConnectionPeer) (int, bool)
}
PathMTUProvider is an optional interface for a Conn that can report the largest datagram the local path towards a peer carries. The connection starts its path-MTU search from that value.
The value is the largest uTP datagram, the UDP payload, not the link MTU. It only lowers the configured MaxPacketSize, never raises it.
type QueuedReader ¶
type QueuedReader interface {
Queued() int
}
QueuedReader is an optional interface for a Conn that can report how many datagrams ReadFrom would return without blocking. The socket reads those before acknowledging, so a run of datagrams already waiting draws one acknowledgement rather than one each. A Conn that implements neither this nor batched reads has each datagram treated as its own batch.
Queued may undercount but must not overcount: every datagram it counts must be returned by ReadFrom without blocking.
type Socket ¶
type Socket struct {
// contains filtered or unexported fields
}
Socket is a uTP endpoint: one datagram transport carrying any number of connections. Create one with Bind or NewSocket.
func Bind ¶
func Bind(ctx context.Context, network string, addr *net.UDPAddr, logger *slog.Logger, opts ...SocketOption) (*Socket, error)
Bind opens a UDP socket on addr and runs a uTP socket on it, which owns it and closes it on Close. logger receives the socket's logging; nil discards it. LevelTrace is its per-packet level.
func NewSocket ¶
NewSocket runs a uTP socket on socket, which remains the caller's. logger receives the socket's logging; nil discards it. LevelTrace is its per-packet level.
func (*Socket) Accept ¶
Accept waits for an incoming connection from any peer and returns it once connected. config applies to the connection; nil means the socket's accept configuration (WithAcceptConfig) or the defaults.
func (*Socket) AcceptBacklog ¶
AcceptBacklog reports how many incoming connections are waiting for an Accept to take them.
func (*Socket) AcceptWithCID ¶
func (s *Socket) AcceptWithCID(ctx context.Context, cid *ConnectionID, config *ConnectionConfig) (*Stream, error)
AcceptWithCID waits for the incoming connection with the given id and returns it once connected. It fails with ErrAcceptTimedOut if no matching SYN arrives within 20 seconds.
func (*Socket) Close ¶
Close shuts the socket down. It is safe to call more than once.
It first waits for streams already closed to finish delivering what was written to them, while each one's peer keeps answering (awaitLingering); everything else ends at once.
func (*Socket) Connect ¶
func (s *Socket) Connect(ctx context.Context, peer ConnectionPeer, config *ConnectionConfig) (*Stream, error)
Connect dials peer with newly chosen connection ids and returns the stream once the handshake completes. ctx bounds the dial only; the connection lives until it is closed or the socket closes. A nil config means the defaults.
func (*Socket) ConnectWithCID ¶
func (s *Socket) ConnectWithCID( ctx context.Context, cid *ConnectionID, config *ConnectionConfig, ) (*Stream, error)
ConnectWithCID is Connect with the connection ids given by cid.
func (*Socket) ConnectionsRefusedAtCapacity ¶
ConnectionsRefusedAtCapacity reports how many incoming connections were refused because the socket was at its connection cap. See WithMaxConnections.
func (*Socket) ConnectionsRefusedByFirewall ¶
ConnectionsRefusedByFirewall reports how many incoming connections the firewall callback rejected.
func (*Socket) ConnectionsRefusedIDInUse ¶
ConnectionsRefusedIDInUse reports how many incoming connections were refused because a connection this socket dialed to the same peer already receives on the id the new one would use.
func (*Socket) LocalAddr ¶
LocalAddr returns the address the underlying socket is bound to, or nil if it cannot report one. After binding to port 0 it reports the chosen port.
func (*Socket) NumConnections ¶
NumConnections returns how many connections the socket currently tracks.
func (*Socket) PacketsDroppedFullConnQueue ¶
PacketsDroppedFullConnQueue reports how many received packets this socket discarded because the destination connection's event queue was full. It should be zero.
func (*Socket) PacketsResetSent ¶
PacketsResetSent reports how many RESETs this socket sent in answer to packets for connections it does not have.
func (*Socket) ProcessICMPError ¶
func (s *Socket) ProcessICMPError(quoted []byte, peer ConnectionPeer) bool
ProcessICMPError reports an ICMP message that should end a connection: destination unreachable other than fragmentation needed, time exceeded, or parameter problem. The connection ends with ErrConnRefused if it had only sent its SYN and ErrReset otherwise.
quoted, peer and the result are as for ProcessICMPFragmentation. Which ICMP messages are fatal is for the caller to decide.
func (*Socket) ProcessICMPFragmentation ¶
func (s *Socket) ProcessICMPFragmentation(quoted []byte, peer ConnectionPeer, nextHopMTU uint16) bool
ProcessICMPFragmentation reports an ICMP "fragmentation needed" message (IPv4 type 3 code 4, or ICMPv6 "packet too big") for a datagram this socket sent, so the path-MTU search can use the router's figure instead of losing a probe to discover it.
quoted is the uTP datagram the ICMP message quoted, the original UDP payload, without the ICMP, IP or UDP headers. peer is the address it was sent to. nextHopMTU is the router's figure, which may be zero; the search halves the gap when it is missing or implausible.
It reports whether quoted was recognized as a packet of a live connection.
The socket does not collect ICMP itself. On Linux the usual source is IP_RECVERR on the UDP socket.
type SocketOption ¶
type SocketOption func(*Socket)
SocketOption configures a Socket at construction.
func WithAcceptConfig ¶
func WithAcceptConfig(config func() *ConnectionConfig) SocketOption
WithAcceptConfig gives the socket its own configuration for incoming connections, read as each one is created. With it, a SYN is answered as it arrives, whether or not an Accept is waiting, and the connection is held until an Accept or AcceptWithCID takes it.
The function's configuration is used for every connection answered before an Accept asks, and for one accepted with a nil config. An Accept given a config of its own still applies it to a connection whose SYN arrives while it waits; one that takes an already answered connection gets it as it was created.
Without this option the configuration comes from each Accept, so a SYN that arrives before its Accept waits, unanswered, until an Accept claims it or 20 seconds pass.
Answered connections count against WithMaxConnections and are held until the application accepts them.
func WithFirewall ¶
func WithFirewall(refuse func(peer ConnectionPeer) bool) SocketOption
WithFirewall refuses incoming connections the callback rejects.
The callback is consulted for a SYN for a connection this socket does not already have, before any state exists for it. Returning true drops the packet without an answer, so a refused peer costs no connection state and learns nothing; a typical use is an IP blocklist.
The callback runs on the socket's receive path. It must not block or call back into the socket.
func WithMaxConnections ¶
func WithMaxConnections(n int) SocketOption
WithMaxConnections limits the connections this socket holds before it refuses new incoming ones. A SYN is refused while the socket holds more than n, so up to n+1 are admitted.
Every connection counts, dialed or accepted, established or closing, as does every SYN waiting for Accept. A refused SYN is dropped silently: a RESET would tell the peer something is listening.
n == 0 means DefaultMaxConnections, the default without this option. n < 0 means no limit.
type Stream ¶
type Stream struct {
// contains filtered or unexported fields
}
Stream is one uTP connection, as returned by Socket's Connect and Accept methods.
It lives as long as the socket, not the call that created it: canceling a dial's or accept's context after it returns does not end the stream. Read and Write each take a context that governs that one call. CloseWrite sends a FIN once what is written has been sent, CloseRead stops delivery, and Close does both and returns at once while the connection delivers what it holds in the background; Socket.Close waits for that while the peer still answers. Done is closed when the connection has ended.
func (*Stream) Close ¶
Close ends the stream and returns at once. What has been written continues to be delivered in the background, followed by the FIN, until the peer has acknowledged everything or stopped answering; Socket.Close waits for that.
func (*Stream) CloseRead ¶
CloseRead shuts down the receiving side: this end stops delivering what the peer sends, while everything it has to send goes out normally.
Incoming data is still acknowledged and then discarded, so the peer is not stalled by a closing window and can finish sending and closing. Data already buffered is discarded too.
Afterwards Read returns ErrReadClosed. Write is unaffected. It is named after net.TCPConn.CloseRead.
func (*Stream) CloseWrite ¶
CloseWrite shuts down the sending side and leaves the receiving side open: everything written is flushed, a FIN follows it, and the peer may continue sending. It is named after net.TCPConn.CloseWrite, so callers holding a net.Conn can detect it with a type assertion.
Afterwards Write returns ErrNotConnected. Read is unaffected and returns data until the peer closes too. Close ends the connection.
func (*Stream) Done ¶
func (s *Stream) Done() <-chan struct{}
Done returns a channel closed once the connection has ended: its close handshake finished or gave up, it was reset or timed out, or the socket closed. Data delivered before then can still be read.
func (*Stream) Read ¶
Read reads the next available bytes into buf, returning as soon as any are available. It returns io.EOF once the peer has closed its sending side and everything it sent has been read.
Do not mix Read and ReadToEOF on the same stream; each would consume chunks the other expected.
func (*Stream) ReadToEOF ¶
ReadToEOF reads until the peer ends the stream, replacing the contents of *buf. It reuses the capacity *buf already has, so a caller that knows how much is coming can size it once.
func (*Stream) SetWindowSize ¶
SetWindowSize sets the upper bound on this connection's congestion window, in bytes, overriding ConnectionConfig.WindowSize. It takes effect at once: nothing more is sent beyond it, and a larger window is cut to it. Zero restores the default.
func (*Stream) WindowSize ¶
WindowSize returns the upper bound set by SetWindowSize or the connection's config.
func (*Stream) Write ¶
Write queues all of buf to be sent and returns once the connection has taken every byte into its send buffer, which may be before any has been sent; delivery continues in the background, through Close.
The count is what the connection took, all of which will be sent. If ctx ends first, Write returns the count taken with ctx's error and withdraws the rest, so retrying with the remainder sends each byte once. Concurrent writes are each sent whole, one after another.
After CloseWrite or Close it returns ErrNotConnected, and once the connection has ended, the reason it ended.
func (*Stream) WriteV ¶
WriteV writes several buffers as one stream write, without the caller joining them first, saving a copy. It returns the number of bytes written, which on success is their sum, and otherwise behaves like Write. Empty and nil buffers are skipped; a call with nothing to write returns 0, nil.
Source Files
¶
- batch_drain_linux.go
- batch_read_unix.go
- cid.go
- clock.go
- clock_drift.go
- congestion.go
- congestion_ledbatpp.go
- conn.go
- conn_ack.go
- conn_close.go
- conn_config.go
- conn_loop.go
- conn_read.go
- conn_receive.go
- conn_recovery.go
- conn_send.go
- delay_set.go
- doc.go
- dont_fragment.go
- dontfragment_linux.go
- dormant.go
- event.go
- global.go
- logging.go
- metrics.go
- mtu.go
- packet.go
- path_mtu.go
- rack.go
- recv_buffer.go
- retransmit_timer.go
- send_buffer.go
- sent_packet.go
- seq.go
- socket_accept.go
- socket_dial.go
- socket_receive.go
- socket_routing.go
- socket_send.go
- socket_udp.go
- stream.go
- sync_map.go
- temporary_error.go
- temporary_error_other.go
- utp_socket.go
- utp_utils.go
Directories
¶
| Path | Synopsis |
|---|---|
|
compat
|
|
|
golibutp
module
|
|
|
internal
|
|
|
netem
Package netem provides an in-process emulated network for testing uTP.
|
Package netem provides an in-process emulated network for testing uTP. |
|
Package utpnet presents a uTP socket through the standard library's net interfaces.
|
Package utpnet presents a uTP socket through the standard library's net interfaces. |