conn

package module
v0.1.3 Latest Latest
Warning

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

Go to latest
Published: May 3, 2026 License: MIT Imports: 22 Imported by: 0

README

BatchUDP

batchudp is a small UDP transport package extracted from wireguard-go/conn. It is for applications that want the WireGuard-style Bind API without pulling in the rest of wireguard-go.

It opens IPv4 and IPv6 UDP sockets on the same port, exposes per-family receive functions, and hides platform-specific details such as batch I/O, sticky source address handling, and Linux UDP GSO/GRO support.

[!IMPORTANT] This project contains code extracted from the original wireguard-go project with some modifications. All credit goes to the original wireguard-go authors.

Usage

package main

import (
	"log"

	conn "github.com/asciimoth/batchudp"
	"github.com/asciimoth/gonnect/native"
)

func main() {
	network := (&native.Config{}).Build()
	defer network.Down()

	bind := conn.NewDefaultBind(network)
	recvFns, port, err := bind.Open(0)
	if err != nil {
		log.Fatal(err)
	}
	defer bind.Close()

	peer, err := bind.ParseEndpoint("127.0.0.1:9000")
	if err != nil {
		log.Fatal(err)
	}

	if err := bind.Send([][]byte{[]byte("ping")}, peer); err != nil {
		log.Fatal(err)
	}

	packets := make([][]byte, bind.BatchSize())
	sizes := make([]int, bind.BatchSize())
	eps := make([]conn.Endpoint, bind.BatchSize())
	for i := range packets {
		packets[i] = make([]byte, 2048)
	}

	n, err := recvFns[0](packets, sizes, eps)
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("listening on %d, received %d packet(s)", port, n)
}

For a larger end-to-end example, see examples/udp_pingpong.

Migration From wireguard-go/conn

Most of the public Bind, Endpoint, and ReceiveFunc shape is intentionally similar, so send/receive code usually moves over with little change.

The main differences are:

  • NewDefaultBind and NewStdNetBind require a gonnect.Network.
  • Network lifecycle is explicit. When using gonnect/native, call network.Down() when the network should be torn down.
  • If you start from an existing gonnect.PacketConn on Linux, use TryUpgradeToBatchingConn to opt into batched reads and writes.

Typical constructor migration:

// wireguard-go/conn
bind := conn.NewDefaultBind()
// batchudp
network := (&native.Config{}).Build()
bind := conn.NewDefaultBind(network)
defer network.Down()

If your old code only depended on the Bind interface after construction, the rest of the call sites should usually keep the same structure: Open, ParseEndpoint, Send, BatchSize, and the returned ReceiveFunc values all work the same way.

Documentation

Overview

Package conn implements WireGuard's network connections.

Index

Constants

View Source
const (
	IdealBatchSize = 128 // maximum number of packets handled per read and write
)
View Source
const StdNetSupportsStickySockets = true

Variables

View Source
var (
	ErrSinglePacketReadUnsupported = errors.New("single-packet reads are unsupported on batching connections")
	ErrBatchTooLarge               = errors.New("batch size exceeds batching connection capacity")
)
View Source
var (
	ErrBindAlreadyOpen    = errors.New("bind is already open")
	ErrReadBufferTooShort = errors.New("receive buffers list shorter than bind batch size")
	ErrNoNetwork          = errors.New("bind network is nil")
	ErrWrongEndpointType  = errors.New("endpoint type does not correspond with bind type")
)

Functions

func MinControlMessageSize

func MinControlMessageSize() int

MinControlMessageSize reports the control buffer size required by ReadBatch.

func TryUpgradeToBatchingConn

func TryUpgradeToBatchingConn(pconn gonnect.PacketConn, network string, batchSize int) gonnect.PacketConn

TryUpgradeToBatchingConn upgrades a native-backed gonnect packet connection to a BatchingConn when Linux batching support is available.

Types

type BatchingConn

type BatchingConn interface {
	gonnect.UDPConn

	// ReadBatch reads one or more datagrams into msgs and returns the number of
	// message slots the caller should inspect. Callers should size each
	// msgs[i].OOB slice capacity to at least MinControlMessageSize().
	ReadBatch(msgs []ipv6.Message, flags int) (n int, err error)

	// WriteBatchTo writes one or more datagrams to addr. The length of bufs must
	// not exceed BatchSize().
	WriteBatchTo(bufs [][]byte, addr netip.AddrPort) error

	// BatchSize reports the maximum number of datagrams expected by ReadBatch
	// and WriteBatchTo for this connection.
	BatchSize() int
}

A BatchingConn is a gonnect UDP connection upgraded with batched I/O.

Callers should prefer ReadBatch over single-packet read methods. A batching connection may receive GRO-coalesced datagrams that cannot be represented by ReadFromUDP or ReadFromUDPAddrPort without losing segmentation context.

type Bind

type Bind interface {
	// Open puts the Bind into a listening state on a given port and reports the
	// actual port that it bound to. Passing zero results in a random selection.
	// fns is the set of functions that will be called to receive packets.
	//
	// Open fails with ErrBindAlreadyOpen if the bind is already open. Callers
	// should treat Open as a lifecycle transition rather than an operation to run
	// concurrently with another Open or Close.
	Open(port uint16) (fns []ReceiveFunc, actualPort uint16, err error)

	// Close closes the Bind listener.
	//
	// Close is safe to race with Send and with ReceiveFuncs returned by Open.
	// All ReceiveFuncs returned by Open must eventually return net.ErrClosed
	// after Close. Repeated Close calls are allowed.
	Close() error

	// SetMark sets the mark for each packet sent through this Bind.
	//
	// On Linux and Android this is SO_MARK; on FreeBSD and OpenBSD the platform
	// equivalent is used; on other platforms this is a no-op. Implementations
	// apply the mark to the currently open sockets, so it should be called after
	// Open and again after reopening a Bind.
	SetMark(mark uint32) error

	// Send writes one or more packets in bufs to address ep. The length of
	// bufs must not exceed BatchSize().
	//
	// Send is safe for concurrent use with other Send calls and with Close.
	// The endpoint must have been created by this Bind implementation's
	// ParseEndpoint, or otherwise be of the implementation-specific endpoint
	// type expected by the Bind. On Linux and Android, StdNetBind may coalesce
	// multiple datagrams into one sendmsg when UDP segmentation offload is
	// available; if the kernel rejects UDP GSO, it is disabled for the socket
	// and the send is retried without offload.
	Send(bufs [][]byte, ep Endpoint) error

	// ParseEndpoint creates a new endpoint from a string.
	//
	// Parsed endpoints are Bind-implementation specific. Endpoint values should
	// be treated as immutable once shared with Send or a ReceiveFunc; mutating an
	// endpoint's cached source state is not required to be thread-safe.
	ParseEndpoint(s string) (Endpoint, error)

	// BatchSize is the number of buffers expected to be passed to
	// the ReceiveFuncs, and the maximum expected to be passed to Send.
	//
	// StdNetBind returns IdealBatchSize on Linux and Android and 1 elsewhere.
	// WinRingBind currently returns 1.
	BatchSize() int
}

A Bind listens on a port for both IPv6 and IPv4 UDP traffic.

A Bind interface may also be a PeekLookAtSocketFd or BindSocketToInterface, depending on the platform-specific implementation.

func NewDefaultBind

func NewDefaultBind(network gonnect.Network) Bind

func NewStdNetBind

func NewStdNetBind(network gonnect.Network) Bind

type BindSocketToInterface

type BindSocketToInterface interface {
	BindSocketToInterface4(interfaceIndex uint32, blackhole bool) error
	BindSocketToInterface6(interfaceIndex uint32, blackhole bool) error
}

BindSocketToInterface is implemented by Bind objects that support being tied to a single network interface. Used by wireguard-windows.

These methods act on already-open sockets. They may also enable blackhole mode for the selected address family, causing subsequent sends for that family to be dropped locally.

type Endpoint

type Endpoint interface {
	ClearSrc()           // clears the source address
	SrcToString() string // returns the local source address (ip:port)
	DstToString() string // returns the destination address (ip:port)
	DstToBytes() []byte  // used for mac2 cookie calculations
	DstIP() netip.Addr
	SrcIP() netip.Addr
}

An Endpoint maintains the source/destination caching for a peer.

dst: the remote address of a peer ("endpoint" in uapi terminology)
src: the local address from which datagrams originate going to the peer

type ErrUDPGSODisabled

type ErrUDPGSODisabled struct {
	RetryErr error
	// contains filtered or unexported fields
}

func (ErrUDPGSODisabled) Error

func (e ErrUDPGSODisabled) Error() string

func (ErrUDPGSODisabled) Unwrap

func (e ErrUDPGSODisabled) Unwrap() error

type PeekLookAtSocketFd

type PeekLookAtSocketFd interface {
	PeekLookAtSocketFd4() (fd int, err error)
	PeekLookAtSocketFd6() (fd int, err error)
}

PeekLookAtSocketFd is implemented by Bind objects that support having their file descriptor peeked at. Used by wireguard-android.

The returned fd is borrowed from the Bind; callers must not close it and should assume it becomes invalid after Close.

type ReceiveFunc

type ReceiveFunc func(packets [][]byte, sizes []int, eps []Endpoint) (n int, err error)

A ReceiveFunc receives at least one packet from the network and writes them into packets. On a successful read it returns the number of elements of sizes, packets, and endpoints that should be evaluated. Some elements of sizes may be zero, and callers should ignore them. Callers must pass packets, sizes, and eps slices with a length greater than or equal to the associated Bind.BatchSize().

ReceiveFuncs returned by Bind.Open remain valid until the next Bind.Close. They are expected to block waiting for input, may be called concurrently with Bind.Send, and must unblock and return net.ErrClosed after Close.

func (ReceiveFunc) PrettyName

func (fn ReceiveFunc) PrettyName() string

type StdNetBind

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

StdNetBind implements Bind for all platforms. While Windows has its own Bind (see bind_windows.go), it may fall back to StdNetBind. TODO: Remove usage of ipv{4,6}.PacketConn when net.UDPConn has comparable methods for sending and receiving multiple datagrams per-syscall. See the proposal in https://github.com/golang/go/issues/45886#issuecomment-1218301564.

func (*StdNetBind) BatchSize

func (s *StdNetBind) BatchSize() int

TODO: When all Binds handle IdealBatchSize, remove this dynamic function and rename the IdealBatchSize constant to BatchSize.

func (*StdNetBind) Close

func (s *StdNetBind) Close() error

func (*StdNetBind) Open

func (s *StdNetBind) Open(uport uint16) ([]ReceiveFunc, uint16, error)

func (*StdNetBind) ParseEndpoint

func (*StdNetBind) ParseEndpoint(s string) (Endpoint, error)

func (*StdNetBind) Send

func (s *StdNetBind) Send(bufs [][]byte, endpoint Endpoint) error

func (*StdNetBind) SetMark

func (s *StdNetBind) SetMark(mark uint32) error

type StdNetEndpoint

type StdNetEndpoint struct {
	// AddrPort is the endpoint destination.
	netip.AddrPort
	// contains filtered or unexported fields
}

func (*StdNetEndpoint) ClearSrc

func (e *StdNetEndpoint) ClearSrc()

func (*StdNetEndpoint) DstIP

func (e *StdNetEndpoint) DstIP() netip.Addr

func (*StdNetEndpoint) DstToBytes

func (e *StdNetEndpoint) DstToBytes() []byte

func (*StdNetEndpoint) DstToString

func (e *StdNetEndpoint) DstToString() string

func (*StdNetEndpoint) SrcIP

func (e *StdNetEndpoint) SrcIP() netip.Addr

func (*StdNetEndpoint) SrcIfidx

func (e *StdNetEndpoint) SrcIfidx() int32

func (*StdNetEndpoint) SrcToString

func (e *StdNetEndpoint) SrcToString() string

Directories

Path Synopsis
examples
udp_pingpong command

Jump to

Keyboard shortcuts

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