Help us shape the future of Go! Take the 2026 Go Developer Survey

utp

package module
v1.5.1 Latest Latest
Warning

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

Go to latest
Published: Aug 17, 2026 License: MIT Imports: 23 Imported by: 27

README

go-libutp

Go Reference Go Go Report Card

A Go wrapper for libutp, BitTorrent's reference implementation of the Micro Transport Protocol (µTP). µTP is a reliable, ordered, stream-oriented transport that runs over UDP and backs off in the presence of competing traffic, so bulk transfers don't saturate the link they share with interactive traffic.

The libutp sources are vendored in this repository, so there's no external C library to install. Building requires cgo and a C++ compiler.

Install

go get github.com/anacrolix/go-libutp

The import path is github.com/anacrolix/go-libutp; the package name is utp.

Usage

Socket implements both net.Listener and net.PacketConn, and the connections it hands out implement net.Conn, so µTP mostly drops into code written against TCP.

Dialling:

s, err := utp.NewSocket("udp", ":0")
if err != nil {
	return err
}
defer s.Close()

c, err := s.DialContext(ctx, "udp", "example.com:4242")
if err != nil {
	return err
}
defer c.Close()

_, err = io.WriteString(c, "hello")

Accepting:

s, err := utp.NewSocket("udp", ":4242")
if err != nil {
	return err
}
defer s.Close()

for {
	c, err := s.Accept()
	if err != nil {
		return err
	}
	go handle(c)
}

Socket.Dial and Socket.DialTimeout are also available for the simpler cases.

Wrapping an existing PacketConn

NewSocketFromPacketConn runs µTP over a net.PacketConn you already have, which is useful when the port is shared with another protocol or comes from elsewhere:

pc, err := net.ListenPacket("udp", ":4242")
if err != nil {
	return err
}
s, err := utp.NewSocketFromPacketConn(pc)
Sharing a port with non-µTP traffic

Packets that aren't µTP are not dropped: Socket implements net.PacketConn, and its ReadFrom and WriteTo carry exactly those packets. That's how a single UDP port can serve µTP connections and something else — a DHT, say — at the same time.

Two caveats on that net.PacketConn: non-µTP packets are buffered and dropped if the reader doesn't keep up, and the deadline methods on Socket are unimplemented (they panic). Deadlines on an accepted or dialled Conn work normally.

Options
  • utp.WithLogger(l) — pass to NewSocket/NewSocketFromPacketConn to give a socket its own logger, instead of the package-level utp.Logger.
  • Socket.SetFirewallCallback and Socket.SetSyncFirewallCallback — reject incoming connections before they're acknowledged, so the peer sees no response at all rather than an accept followed by a close. Prefer the synchronous variant; it's called under the package lock and is consulted for every incoming connection.
  • Socket.SetOption — set the underlying libutp context options directly.

ucat

cmd/ucat is a netcat-alike over µTP, handy for smoke-testing:

go run ./cmd/ucat -l :4242         # listen
go run ./cmd/ucat localhost:4242   # dial, then pipe stdin/stdout

Development

The justfile mirrors the CI jobs, so what you run locally is what CI runs:

just test    # go test -race -count 2 ./...
just bench   # build/smoke the benchmarks
just asan    # tests under LeakSanitizer

just asan is clean on Linux and macOS; see lsan_suppressions.txt for the macOS system-library allocations it has to ignore.

Release history

See CHANGELOG.md.

License

MIT, inherited from libutp. See LICENSE.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrConnClosed = errors.New("closed")
)
View Source
var Logger = log.Default.WithContextText("go-libutp")

The default Socket Logger. Override per Socket by using WithLogger with NewSocket.

Functions

func WriteStatus

func WriteStatus(w io.Writer)

Types

type Conn

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

func (*Conn) Close

func (c *Conn) Close() error

func (*Conn) LocalAddr

func (c *Conn) LocalAddr() net.Addr

func (*Conn) OnError

func (c *Conn) OnError(f func(error))

func (*Conn) Read

func (c *Conn) Read(b []byte) (int, error)

func (*Conn) RemoteAddr

func (c *Conn) RemoteAddr() net.Addr

func (*Conn) SetDeadline

func (c *Conn) SetDeadline(t time.Time) error

func (*Conn) SetReadDeadline

func (c *Conn) SetReadDeadline(t time.Time) error

func (*Conn) SetWriteBufferLen

func (c *Conn) SetWriteBufferLen(len int)

func (*Conn) SetWriteDeadline

func (c *Conn) SetWriteDeadline(t time.Time) error

func (*Conn) Write

func (c *Conn) Write(b []byte) (n int, err error)

func (*Conn) WriteBufferLen

func (c *Conn) WriteBufferLen() int

type FirewallCallback

type FirewallCallback func(net.Addr) bool

A firewall callback returns true if an incoming connection request should be ignored. This is better than just accepting and closing, as it means no acknowledgement packet is sent.

type NewSocketOpt added in v1.2.0

type NewSocketOpt func(s *Socket)

func WithLogger added in v1.2.0

func WithLogger(l log.Logger) NewSocketOpt

type Option

type Option = C.int
const (
	LogNormal   Option = C.UTP_LOG_NORMAL
	LogMtu      Option = C.UTP_LOG_MTU
	LogDebug    Option = C.UTP_LOG_DEBUG
	SendBuffer  Option = C.UTP_SNDBUF
	RecvBuffer  Option = C.UTP_RCVBUF
	TargetDelay Option = C.UTP_TARGET_DELAY

	TimedOut = C.UTP_ETIMEDOUT
)

type Socket

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

func NewSocket

func NewSocket(network, addr string, opts ...NewSocketOpt) (*Socket, error)

func NewSocketFromPacketConn added in v1.5.0

func NewSocketFromPacketConn(pc net.PacketConn, opts ...NewSocketOpt) (*Socket, error)

func (*Socket) Accept

func (s *Socket) Accept() (net.Conn, error)

func (*Socket) Addr

func (s *Socket) Addr() net.Addr

func (*Socket) Close

func (s *Socket) Close() error

func (*Socket) Dial

func (s *Socket) Dial(addr string) (net.Conn, error)

func (*Socket) DialContext

func (s *Socket) DialContext(ctx context.Context, network, addr string) (_ net.Conn, err error)

Passing an empty network will use the network of the Socket's listener.

func (*Socket) DialTimeout

func (s *Socket) DialTimeout(addr string, timeout time.Duration) (net.Conn, error)

func (*Socket) LocalAddr

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

func (*Socket) ReadBufferLen

func (s *Socket) ReadBufferLen() int

func (*Socket) ReadFrom

func (s *Socket) ReadFrom(b []byte) (n int, addr net.Addr, err error)

func (*Socket) SetDeadline

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

func (*Socket) SetFirewallCallback

func (s *Socket) SetFirewallCallback(f FirewallCallback)

The callback is used before each packet is processed by libutp without the this package's mutex being held. libutp may not actually need the result as the packet might not be a connection attempt. If the callback function is expensive, it may be worth setting a synchronous callback using SetSyncFirewallCallback.

func (*Socket) SetOption

func (s *Socket) SetOption(opt Option, val int) int

func (*Socket) SetReadDeadline

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

func (*Socket) SetSyncFirewallCallback added in v1.1.0

func (s *Socket) SetSyncFirewallCallback(f FirewallCallback)

SetSyncFirewallCallback sets a synchronous firewall callback. It's only called as needed by libutp. It is called with the package-wide mutex held. Any locks acquired by the callback should not also be held by code that might use this package.

func (*Socket) SetWriteBufferLen

func (s *Socket) SetWriteBufferLen(len int)

func (*Socket) SetWriteDeadline

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

func (*Socket) WriteBufferLen

func (s *Socket) WriteBufferLen() int

func (*Socket) WriteTo

func (s *Socket) WriteTo(b []byte, addr net.Addr) (int, error)

Directories

Path Synopsis
cmd
ucat command

Jump to

Keyboard shortcuts

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