zerocopy

package
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Sep 10, 2022 License: AGPL-3.0 Imports: 12 Imported by: 0

Documentation

Overview

Package zerocopy defines interfaces and helper functions for zero-copy read/write operations.

Index

Constants

View Source
const (
	IPv4HeaderLength = 20
	IPv6HeaderLength = 40
	UDPHeaderLength  = 8
)

Used in packet size calculations.

Variables

View Source
var (
	ErrPacketTooSmall = errors.New("packet too small to unpack")
	ErrPayloadTooBig  = errors.New("payload too big to pack")
)
View Source
var ErrAcceptDoneNoRelay = errors.New("the accepted connection has been handled without relaying")

Functions

func ClientServerPackUnpackerTestFunc added in v1.1.0

func ClientServerPackUnpackerTestFunc(t *testing.T, c ClientPackUnpacker, s ServerPackUnpacker)

ClientServerPackUnpackerTestFunc tests the client pack-unpacker and the server pack-unpacker with the following precedure: 1. Client packer packs. 2. Server unpacker unpacks. 3. Server packer packs. 4. Client unpacker unpacks.

func CloseWriteDrain

func CloseWriteDrain(conn *net.TCPConn, serverName, listenAddress, clientAddress string, logger *zap.Logger)

CloseWriteDrain closes the write end of the TCP connection, then drain the read end.

func CopyWriteOnce

func CopyWriteOnce(rw ReadWriter, b []byte) (n int, err error)

func ForceReset

func ForceReset(conn *net.TCPConn, serverName, listenAddress, clientAddress string, logger *zap.Logger)

ForceReset forces a reset of the TCP connection, regardless of whether there's unread data or not.

func MaxPacketSizeForAddr

func MaxPacketSizeForAddr(mtu int, addr netip.Addr) int

MaxPacketSizeForAddr calculates the maximum packet size for the given address based on the MTU and the address family.

func ReadWriterTestFunc

func ReadWriterTestFunc(t *testing.T, l, r ReadWriter)

ReadWriterTestFunc tests the left and right ReadWriters by performing 2 writes on each ReadWriter and validating the read results.

The left and right ReadWriters must be connected with a duplex pipe.

func Relay

func Relay(w Writer, r Reader) (n int64, err error)

Relay reads from r and writes to w using zero-copy methods. It returns the number of bytes transferred, and any error occurred during transfer.

func ReplyWithGibberish added in v1.2.0

func ReplyWithGibberish(conn *net.TCPConn, serverName, listenAddress, clientAddress string, logger *zap.Logger)

ReplyWithGibberish keeps reading and replying with random garbage until EOF or error.

func TwoWayRelay

func TwoWayRelay(left, right ReadWriter) (nl2r, nr2l int64, err error)

TwoWayRelay relays data between left and right using zero-copy methods. It returns the number of bytes sent from left to right, from right to left, and any error occurred during transfer.

Types

type ClientPackUnpacker added in v1.1.0

type ClientPackUnpacker interface {
	ClientPacker
	ClientUnpacker
}

ClientPackUnpacker implements both ClientPacker and ClientUnpacker interfaces.

type ClientPacker added in v1.1.0

type ClientPacker interface {
	Headroom

	// PackInPlace packs the payload in-place into a packet ready for sending and returns
	// the destination address, packet start offset, packet length, or an error if packing fails.
	PackInPlace(b []byte, targetAddr conn.Addr, payloadStart, payloadLen int) (destAddrPort netip.AddrPort, packetStart, packetLen int, err error)
}

ClientPacker processes raw payload into packets ready to be sent to servers.

type ClientUnpacker added in v1.1.0

type ClientUnpacker interface {
	Headroom

	// UnpackInPlace unpacks the packet in-place and returns packet source address, payload start offset, payload length, or an error if unpacking fails.
	UnpackInPlace(b []byte, packetSourceAddrPort netip.AddrPort, packetStart, packetLen int) (payloadSourceAddrPort netip.AddrPort, payloadStart, payloadLen int, err error)
}

ClientUnpacker processes packets received from the server into raw payload.

type CloseRead

type CloseRead interface {
	// CloseRead indicates to the underlying reader that no further reads will happen.
	CloseRead() error
}

CloseRead provides the CloseRead method.

type CloseWrite

type CloseWrite interface {
	// CloseWrite indicates to the underlying writer that no further writes will happen.
	CloseWrite() error
}

CloseWrite provides the CloseWrite method.

type CopyReadWriter

type CopyReadWriter struct {
	ReadWriter
	// contains filtered or unexported fields
}

CopyReadWriter wraps a ReadWriter and provides the io.ReadWriter Read and Write methods by copying from and to internal buffers and using the zerocopy methods on them.

The io.ReaderFrom ReadFrom method is implemented using the internal write buffer without copying.

func NewCopyReadWriter

func NewCopyReadWriter(rw ReadWriter) *CopyReadWriter

func (*CopyReadWriter) Read

func (rw *CopyReadWriter) Read(b []byte) (n int, err error)

Read implements the io.Reader Read method.

func (*CopyReadWriter) ReadFrom added in v1.1.0

func (rw *CopyReadWriter) ReadFrom(r io.Reader) (n int64, err error)

ReadFrom implements the io.ReaderFrom ReadFrom method.

func (*CopyReadWriter) Write

func (rw *CopyReadWriter) Write(b []byte) (n int, err error)

Write implements the io.Writer Write method.

type DirectReadCloser

type DirectReadCloser interface {
	// DirectReadCloser returns the underlying reader for direct reads.
	DirectReadCloser() io.ReadCloser
}

DirectReadCloser provides access to the underlying io.ReadCloser.

type DirectReadWriteCloser

type DirectReadWriteCloser interface {
	io.ReadWriteCloser
	CloseRead
	CloseWrite
}

DirectReadWriteCloser extends io.ReadWriteCloser with CloseRead and CloseWrite.

type DirectWriteCloser

type DirectWriteCloser interface {
	// DirectWriteCloser returns the underlying writer for direct writes.
	DirectWriteCloser() io.WriteCloser
}

DirectWriteCloser provides access to the underlying io.WriteCloser.

type Headroom

type Headroom interface {
	// FrontHeadroom returns the minimum space required at the beginning of the buffer before payload.
	FrontHeadroom() int

	// RearHeadroom returns the minimum space required at the end of the buffer after payload.
	RearHeadroom() int
}

Headroom is implemented by readers and writers that require extra buffer space as headroom in read/write calls.

type InitialPayloader

type InitialPayloader interface {
	// NativeInitialPayload reports whether the protocol natively supports
	// sending the initial payload within or along with the request header.
	//
	// No matter true or false, the Dial method must process the initial payload.
	//
	// When false, the Accept method will not return non-empty initial payload.
	NativeInitialPayload() bool
}

InitialPayloader is implemented by a protocol's TCP client or server when the protocol's initial handshake message can carry payload.

type ReadWriter

type ReadWriter interface {
	Reader
	Writer
	CloseRead
	CloseWrite
}

ReadWriter provides a stream interface for reading and writing.

type Reader

type Reader interface {
	Headroom

	// MinPayloadBufferSizePerRead returns the minimum size of payload buffer
	// the ReadZeroCopy method requires for an unbuffered read.
	//
	// This is usually required by chunk-based protocols to be able to read
	// whole chunks without needing internal caching.
	MinPayloadBufferSizePerRead() int

	// ReadZeroCopy uses b as buffer space to initiate a read operation.
	//
	// b must have at least FrontOverhead() bytes before payloadBufStart
	// and RearOverhead() bytes after payloadBufStart + payloadBufLen.
	//
	// payloadBufLen must be at least MinPayloadBufferSizePerRead().
	//
	// The read operation may use the whole space of b.
	// The actual payload will be confined in [payloadBufStart, payloadBufLen).
	//
	// If no error occurs, the returned payload is b[payloadBufStart : payloadBufStart+payloadLen].
	ReadZeroCopy(b []byte, payloadBufStart, payloadBufLen int) (payloadLen int, err error)

	io.Closer
}

Reader provides a stream interface for reading.

type ServerPackUnpacker added in v1.1.0

type ServerPackUnpacker interface {
	ServerPacker
	ServerUnpacker
}

ServerPackUnpacker implements both ServerPacker and ServerUnpacker interfaces.

type ServerPacker added in v1.1.0

type ServerPacker interface {
	Headroom

	// PackInPlace packs the payload in-place into a packet ready for sending and returns
	// packet start offset, packet length, or an error if packing fails.
	PackInPlace(b []byte, sourceAddrPort netip.AddrPort, payloadStart, payloadLen, maxPacketLen int) (packetStart, packetLen int, err error)
}

ServerPacker processes raw payload into packets ready to be sent to clients.

type ServerUnpacker added in v1.1.0

type ServerUnpacker interface {
	Headroom

	// UnpackInPlace unpacks the packet in-place and returns target address, payload start offset, payload length, or an error if unpacking fails.
	UnpackInPlace(b []byte, sourceAddrPort netip.AddrPort, packetStart, packetLen int) (targetAddr conn.Addr, payloadStart, payloadLen int, err error)
}

ServerUnpacker processes packets received from the client into raw payload.

type SimpleUDPClient

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

SimpleUDPClient wraps a PackUnpacker and uses it for all sessions.

SimpleUDPClient implements the UDPClient interface.

func NewSimpleUDPClient

func NewSimpleUDPClient(p ClientPackUnpacker, maxPacketSize, fwmark, frontHeadroom, rearHeadroom int) *SimpleUDPClient

NewSimpleUDPClient wraps a PackUnpacker into a UDPClient and uses it for all sessions.

func (*SimpleUDPClient) FrontHeadroom

func (c *SimpleUDPClient) FrontHeadroom() int

FrontHeadroom implements the UDPClient FrontHeadroom method.

func (*SimpleUDPClient) LinkInfo added in v1.1.0

func (c *SimpleUDPClient) LinkInfo() (int, int)

LinkInfo implements the UDPClient LinkInfo method.

func (*SimpleUDPClient) NewSession

func (c *SimpleUDPClient) NewSession() (ClientPacker, ClientUnpacker, error)

NewSession implements the UDPClient NewSession method.

func (*SimpleUDPClient) RearHeadroom

func (c *SimpleUDPClient) RearHeadroom() int

RearHeadroom implements the UDPClient RearHeadroom method.

type TCPClient

type TCPClient interface {
	InitialPayloader

	// Dial creates a connection to the target address under the protocol's
	// encapsulation and returns the established connection and a ReadWriter for read-write access.
	Dial(targetAddr conn.Addr, payload []byte) (tfoConn tfo.Conn, rw ReadWriter, err error)
}

TCPClient is a protocol's TCP client.

type TCPConnCloser

type TCPConnCloser func(conn *net.TCPConn, serverName, listenAddress, clientAddress string, logger *zap.Logger)

TCPConnCloser handles a potentially malicious TCP connection. Upon returning, the TCP connection is safe to close.

func ParseRejectPolicy

func ParseRejectPolicy(rejectPolicy string, server TCPServer) (TCPConnCloser, error)

ParseRejectPolicy parses a string representation of a reject policy.

func (TCPConnCloser) Do

func (c TCPConnCloser) Do(conn *net.TCPConn, serverName, listenAddress, clientAddress string, logger *zap.Logger)

Do invokes the TCPConnCloser if it's not nil.

type TCPServer

type TCPServer interface {
	InitialPayloader

	// Accept takes a newly-accepted TCP connection and wraps it into a
	// protocol stream server.
	//
	// If the returned error is ErrAcceptDoneNoRelay, the connection has been handled by this method.
	// Two-way relay is not needed.
	Accept(conn tfo.Conn) (rw ReadWriter, targetAddr conn.Addr, payload []byte, err error)

	// DefaultTCPConnCloser returns the default function to handle the closing
	// of a potentially malicious TCP connection.
	//
	// If no special handling is required, return nil.
	DefaultTCPConnCloser() TCPConnCloser
}

TCPServer provides a protocol's TCP service.

type UDPClient

type UDPClient interface {
	// Headroom reports client packer headroom requirements.
	Headroom

	// LinkInfo returns the maximum size of outgoing packets and fwmark.
	LinkInfo() (maxPacketSize, fwmark int)

	// NewSession creates a new session and returns the packet packer
	// and unpacker for the session, or an error.
	NewSession() (ClientPacker, ClientUnpacker, error)
}

UDPClient stores information for creating new client sessions.

type UDPNATServer added in v1.1.0

type UDPNATServer interface {
	// Headroom reports server pack-unpacker headroom requirements.
	Headroom

	// NewSession creates a new session and returns the packet packer
	// and unpacker for the session, or an error.
	NewSession() (ServerPacker, ServerUnpacker, error)
}

UDPNATServer stores information for creating new server sessions.

type UDPSessionServer added in v1.1.0

type UDPSessionServer interface {
	// Headroom reports server unpacker headroom requirements.
	Headroom

	// SessionInfo extracts session ID from a received packet b.
	//
	// The returned session ID is then used by the caller to look up the session table.
	// If no matching entries were found, NewUnpacker should be called to create a new
	// packet unpacker for the packet.
	SessionInfo(b []byte) (csid uint64, err error)

	// NewUnpacker creates a new packet unpacker for the specified client session.
	//
	// The returned unpacker is then used by the caller to unpack the incoming packet.
	// Upon successful unpacking, NewPacker should be called to create a corresponding
	// server session.
	NewUnpacker(b []byte, csid uint64) (ServerUnpacker, error)

	// NewPacker creates a new server session for the specified client session
	// and returns the server session's packer, or an error.
	NewPacker(csid uint64) (ServerPacker, error)
}

UDPSessionServer deals with incoming sessions.

type Writer

type Writer interface {
	Headroom

	// MaxPayloadSizePerWrite returns the maximum size of payload
	// the WriteZeroCopy method can write at a time.
	//
	// This is usually required by chunk-based protocols to be able to write
	// one chunk at a time without needing to break up the payload.
	//
	// If there isn't a maximum limit, return 0.
	MaxPayloadSizePerWrite() int

	// WriteZeroCopy uses b as buffer space to initiate a write operation.
	//
	// b must have at least FrontOverhead() bytes before payloadBufStart
	// and RearOverhead() bytes after payloadBufStart + payloadBufLen.
	//
	// payloadLen must not be greater than MaxPayloadSizePerWrite().
	//
	// The write operation may use the whole space of b.
	WriteZeroCopy(b []byte, payloadStart, payloadLen int) (payloadWritten int, err error)

	io.Closer
}

Writer provides a stream interface for writing.

type ZeroHeadroom

type ZeroHeadroom struct{}

ZeroHeadroom can be embedded by types that have zero headroom.

func (ZeroHeadroom) FrontHeadroom

func (z ZeroHeadroom) FrontHeadroom() int

FrontHeadroom implements the Headroom FrontHeadroom method.

func (ZeroHeadroom) RearHeadroom

func (z ZeroHeadroom) RearHeadroom() int

RearHeadroom implements the Headroom RearHeadroom method.

Jump to

Keyboard shortcuts

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