Go wrapper of libutp reference uTP C implementation
105
stars
294
commits
C++
primary language
Sep 11, 2026
updated
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.
go get github.com/anacrolix/go-libutp
The import path is github.com/anacrolix/go-libutp; the package name is utp.
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.
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)
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.
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.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
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.
See CHANGELOG.md.
MIT, inherited from libutp. See LICENSE.
C++
68.2%
Go
19.1%
C
8.9%
Python
3.5%
Go wrapper of libutp reference uTP C implementation
105
stars
294
commits
C++
primary language
Sep 11, 2026
updated
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.
go get github.com/anacrolix/go-libutp
The import path is github.com/anacrolix/go-libutp; the package name is utp.
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.
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)
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.
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.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
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.
See CHANGELOG.md.
MIT, inherited from libutp. See LICENSE.
C++
68.2%
Go
19.1%
C
8.9%
Python
3.5%