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

lossyconn

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Nov 2, 2026 License: MIT Imports: 12 Imported by: 0

README

lossyconn

GoDoc MIT licensed Coverage Status Created at

lossyconn is an in-memory, packet-oriented network simulator for Go tests. It implements net.PacketConn and can simulate one-way delay, delay variation, bandwidth limits, congestion queueing, link outages, maximum packet sizes and lifetimes, random and burst packet loss, packet duplication and payload corruption, packet reordering, and bounded queues. A fixed seed makes a simulation reproducible.

Quick start

Create two simulated endpoints and send a datagram:

left, err := lossyconn.NewLossyConn(0.3, 200) // 30% loss, 200 ms one-way delay
if err != nil {
	return err
}
defer left.Close()

right, err := lossyconn.NewLossyConn(0.2, 180)
if err != nil {
	return err
}
defer right.Close()

payload := []byte("hello")
if _, err := left.WriteTo(payload, right.LocalAddr()); err != nil {
	return err
}

buf := make([]byte, 1024)
if err := right.SetReadDeadline(time.Now().Add(time.Second)); err != nil {
	return err
}
n, from, err := right.ReadFrom(buf)
if err != nil {
	return err
}
fmt.Printf("received %q from %v\n", buf[:n], from)

Import fmt, time, and github.com/xtaci/lossyconn in the example's package. NewLossyConn keeps the legacy constructor signature; use NewWithConfig for the additional simulation options.

conn, err := lossyconn.NewWithConfig(lossyconn.Config{
	Delay:                50 * time.Millisecond,
	DelayDeviation:       2, // standard deviation, in milliseconds
	BandwidthBytesPerSec: 2 * 1024 * 1024,
	MaxPacketSize:        1200,
	PacketLifetime:       2 * time.Second,
	QueueDelayPerPacket:  2 * time.Millisecond,
	MaxQueueDelay:        100 * time.Millisecond,
	RandomLossRate:       0.01,
	BurstLossRate:        0.002,
	BurstLength:          3,
	DuplicateRate:        0.001,
	CorruptionRate:       0.0001,
	ReorderRate:          0.02,
	MaxReorderDelay:      8 * time.Millisecond,
	QueueSize:            4096,
	MaxPendingPackets:    4096,
	Seed:                 42,
})
if err != nil {
	return err
}
defer conn.Close()

Config fields:

  • Delay: base one-way delay.
  • DelayDeviation: standard deviation of normally distributed delay variation, in milliseconds.
  • BandwidthBytesPerSec: maximum outgoing bandwidth; zero disables shaping.
  • MaxPacketSize: maximum outgoing payload size in bytes; zero disables the limit. Larger packets are counted as sent but dropped before delivery.
  • PacketLifetime: maximum time a packet may remain in transit; zero disables expiration. Expired packets are discarded and counted by the receiving connection.
  • QueueDelayPerPacket and MaxQueueDelay: add delay based on the number of packets already waiting in the outgoing queue, capped at MaxQueueDelay. MaxQueueDelay must be positive when queue delay is enabled. Both values are zero by default.
  • RandomLossRate: independent packet-loss probability from 0 to 1.
  • BurstLossRate and BurstLength: probability and length of consecutive packet-loss bursts.
  • DuplicateRate: probability of scheduling one additional copy of an outgoing packet. Both copies are accepted or rejected together by the bounded send queue.
  • CorruptionRate: probability of flipping one random payload bit in an outgoing packet. Empty payloads are not corrupted.
  • ReorderRate and MaxReorderDelay: probability and maximum extra delay for reordering.
  • QueueSize: maximum number of received packets buffered per connection.
  • MaxPendingPackets: maximum number of outgoing packets waiting for delivery. When this queue is full, WriteTo returns an error. Zero selects the default limit of 4096 packets for both queue limits.
  • Seed: deterministic random seed; zero selects a time-based seed.

Simulated packet loss is reported as a successful WriteTo, matching the behavior of sending a datagram over a lossy network. Queue overflow, unreachable destinations, and expired write deadlines return errors. Read deadlines return an error that implements net.Error.

Use SetLinkState(false) to simulate an outgoing link outage and SetLinkState(true) to restore it. Writes during an outage still succeed, but the packets are discarded and counted in DropLinkDown.

Each destination can have independent delay, bandwidth, loss, queue shaping, and link state. The profile's Config uses the same link settings documented above; receive/send queue limits and random seed remain connection-wide:

if err := left.SetPeerProfile(right.LocalAddr(), lossyconn.LinkProfile{
	Config: lossyconn.Config{
		Delay:          80 * time.Millisecond,
		DelayDeviation: 2,
		RandomLossRate: 0.02,
	},
	Up: true,
}); err != nil {
	return err
}

SchedulePeerProfile adds a complete profile that takes effect for writes started at or after a specified time. Schedule multiple profiles to model changing conditions such as congestion followed by recovery; each scheduled profile replaces, rather than merges with, the previous one. Schedule another profile with Up: true to restore a link after a simulated outage. SetPeerLinkState changes one peer's state immediately, and ClearPeerProfile returns it to the connection's default profile. Statistics are aggregated per connection.

Observe simulation statistics

Stats returns a per-connection snapshot. Receive-side counters include queue and expired-packet drops. ResetStats clears the counters:

stats := conn.Stats()
fmt.Printf("sent=%d received=%d duplicated=%d corrupted=%d random drops=%d oversized drops=%d expired drops=%d link-down drops=%d queue-delayed=%d receive queue drops=%d send queue drops=%d\n",
	stats.SentPackets, stats.RecvPackets, stats.DuplicatedPackets, stats.CorruptedPackets,
	stats.DropRandom, stats.DropOversize, stats.DropExpired, stats.DropLinkDown,
	stats.QueueDelayedPackets, stats.DropQueue, stats.DropPendingQueue)
conn.ResetStats()

NewLossyPacketConn(loss, delayMs) is retained as a deprecated alias of NewLossyConn.

Documentation

Overview

Package lossyconn provides an in-memory packet connection simulator.

It supports configurable delay, bandwidth limits, packet loss, packet size and lifetime limits, duplication, corruption, reordering, and bounded queues for network testing. Outgoing profiles can be configured and scheduled per destination.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Address

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

Address is the opaque local address of a simulated connection.

func NewAddress

func NewAddress() *Address

NewAddress creates a simulated address using cryptographically random bytes.

func (*Address) Network

func (addr *Address) Network() string

Network returns the simulated network name.

func (*Address) String

func (addr *Address) String() string

String returns the opaque simulated address.

type Config added in v1.1.0

type Config struct {
	// One-way base delay.
	Delay time.Duration
	// Standard deviation of normally distributed delay variation, in milliseconds.
	DelayDeviation float64
	// Maximum outgoing bandwidth in bytes per second. Zero disables shaping.
	BandwidthBytesPerSec uint64
	// Maximum outgoing payload size in bytes. Zero disables the limit.
	MaxPacketSize int
	// Maximum time a packet may remain in transit. Zero disables expiration.
	PacketLifetime time.Duration
	// Added delay per packet already waiting in the outgoing queue.
	QueueDelayPerPacket time.Duration
	// Maximum congestion delay. Required when QueueDelayPerPacket is positive.
	MaxQueueDelay time.Duration
	// Probability of independently dropping each outgoing packet, in [0, 1].
	RandomLossRate float64
	// Probability of starting a burst-loss event for an outgoing packet, in [0, 1].
	BurstLossRate float64
	// Number of consecutive packets dropped when a burst-loss event starts.
	BurstLength int
	// Probability of duplicating an outgoing packet, in [0, 1].
	DuplicateRate float64
	// Probability of corrupting an outgoing packet payload, in [0, 1].
	CorruptionRate float64
	// Probability of adding an extra delay to an outgoing packet, in [0, 1].
	ReorderRate float64
	// Maximum extra delay used when reordering a packet.
	MaxReorderDelay time.Duration
	// Maximum number of received packets buffered by each connection. Zero uses the default.
	QueueSize int
	// Maximum number of packets waiting in the outgoing queue. Zero uses the default.
	MaxPendingPackets int
	// Seed for deterministic simulation. Zero selects a time-based seed.
	Seed int64
}

Config controls link simulation behavior.

type ConnectionManager

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

ConnectionManager indexes simulated connections by local address.

func NewConnectionManager

func NewConnectionManager() *ConnectionManager

NewConnectionManager creates an empty connection manager.

func (*ConnectionManager) Delete

func (mgr *ConnectionManager) Delete(conn *LossyConn)

Delete removes conn from the manager.

func (*ConnectionManager) Get

func (mgr *ConnectionManager) Get(addr string) *LossyConn

Get returns the connection registered for addr, or nil if none exists.

func (*ConnectionManager) Set

func (mgr *ConnectionManager) Set(conn *LossyConn)

Set registers conn by its local address.

type LinkProfile added in v1.1.0

type LinkProfile struct {
	Config Config
	Up     bool
}

LinkProfile describes the outgoing link to one peer. Config contains the link behavior; connection-wide queue limits and seed are ignored.

type LossyConn

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

LossyConn is an in-memory net.PacketConn with configurable network effects.

func NewLossyConn

func NewLossyConn(loss float64, delay int) (*LossyConn, error)

NewLossyConn creates a connection with a packet-loss probability and delay.

loss must be in [0, 1]. delay is the one-way delay in milliseconds.

Use NewWithConfig to configure additional network effects.

func NewLossyPacketConn deprecated added in v1.1.0

func NewLossyPacketConn(loss float64, delay int) (*LossyConn, error)

NewLossyPacketConn is kept for backward compatibility.

Deprecated: use NewLossyConn or NewWithConfig.

func NewWithConfig added in v1.1.0

func NewWithConfig(cfg Config) (*LossyConn, error)

NewWithConfig creates a configurable lossy packet connection. Invalid probabilities, negative delay and packet limits, and negative outgoing queue limits return an error. Non-positive receive queue limits and zero outgoing limits select the default capacity of 4096 packets.

func (*LossyConn) ClearPeerProfile added in v1.1.0

func (conn *LossyConn) ClearPeerProfile(addr net.Addr) error

ClearPeerProfile removes the profile and scheduled changes for addr.

func (*LossyConn) Close

func (conn *LossyConn) Close() error

Close closes the connection, unblocks blocked reads, stops its sender, and discards packets that have not yet been delivered.

func (*LossyConn) LocalAddr

func (conn *LossyConn) LocalAddr() net.Addr

LocalAddr returns the connection's simulated local address.

func (*LossyConn) Read

func (conn *LossyConn) Read(b []byte) (int, error)

Read implements the net.Conn Read method.

func (*LossyConn) ReadFrom

func (conn *LossyConn) ReadFrom(p []byte) (n int, addr net.Addr, err error)

ReadFrom reads one packet, copying its payload into p and returning its source address. The returned byte count is between zero and len(p); if p is too small, the remainder of the packet is discarded. If no packet is available before a configured read deadline, the method returns a net.Error with Timeout() == true.

func (*LossyConn) RemoteAddr

func (conn *LossyConn) RemoteAddr() net.Addr

RemoteAddr returns nil because a simulated connection can send to multiple peers.

func (*LossyConn) ResetStats added in v1.1.0

func (conn *LossyConn) ResetStats()

ResetStats resets all counters, including the observed maximum delay.

func (*LossyConn) SchedulePeerProfile added in v1.1.0

func (conn *LossyConn) SchedulePeerProfile(addr net.Addr, at time.Time, profile LinkProfile) error

SchedulePeerProfile schedules a complete outgoing link profile for addr. The profile takes effect for writes started at or after at.

func (*LossyConn) SetDeadline

func (conn *LossyConn) SetDeadline(t time.Time) error

SetDeadline sets both read and write deadlines. It is equivalent to calling SetReadDeadline and SetWriteDeadline with the same absolute time.

A deadline applies to current and future operations. Reads already in progress are woken when the deadline changes. A read with no available packet waits until data arrives, the connection closes, or the deadline expires. WriteTo checks its deadline before scheduling a packet. Setting a later deadline allows subsequent operations to proceed.

A zero time disables deadlines.

func (*LossyConn) SetDelayDeviation

func (conn *LossyConn) SetDelayDeviation(deviation float64) error

SetDelayDeviation sets the delay variation's standard deviation in milliseconds. The value must be finite and non-negative. The configured base delay is unchanged.

func (*LossyConn) SetLinkState added in v1.1.0

func (conn *LossyConn) SetLinkState(up bool)

SetLinkState enables or disables the default outgoing link profile. Explicit peer profiles are not affected.

func (*LossyConn) SetPeerLinkState added in v1.1.0

func (conn *LossyConn) SetPeerLinkState(addr net.Addr, up bool) error

SetPeerLinkState changes the up/down state of addr's outgoing link. Scheduled profiles take precedence once their activation time is reached.

func (*LossyConn) SetPeerProfile added in v1.1.0

func (conn *LossyConn) SetPeerProfile(addr net.Addr, profile LinkProfile) error

SetPeerProfile sets the outgoing link profile for addr. The profile replaces the default link settings rather than merging with them.

func (*LossyConn) SetReadDeadline

func (conn *LossyConn) SetReadDeadline(t time.Time) error

SetReadDeadline sets the deadline for current and future ReadFrom calls. A zero time disables the read deadline.

func (*LossyConn) SetWriteDeadline

func (conn *LossyConn) SetWriteDeadline(t time.Time) error

SetWriteDeadline sets the deadline checked by current and future WriteTo calls. WriteTo does not block while waiting for delivery. A zero time disables the write deadline.

func (*LossyConn) Stats added in v1.1.0

func (conn *LossyConn) Stats() Stats

Stats returns a snapshot of the connection's counters.

func (*LossyConn) String

func (conn *LossyConn) String() string

String returns a summary of packet, byte, loss, and delay statistics.

func (*LossyConn) Write

func (conn *LossyConn) Write(p []byte) (n int, err error)

Write implements net.Conn Write. LossyConn is packet-oriented, so stream writes are unsupported.

func (*LossyConn) WriteTo

func (conn *LossyConn) WriteTo(p []byte, addr net.Addr) (n int, err error)

WriteTo schedules p for delivery to addr. It returns an error if addr is not reachable, the write deadline has expired, the bounded outgoing queue is full, or the connection is closing. Simulated packet loss is reported as a successful write, as with a network send.

type Packet

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

Packet is a payload scheduled for delivery to a simulated connection.

type Stats added in v1.1.0

type Stats struct {
	// Packets discarded by independent random loss.
	DropRandom uint64
	// Packets discarded by burst loss.
	DropBurst uint64
	// Packets discarded because the receive queue was full.
	DropQueue uint64
	// Packets discarded because their payload exceeded MaxPacketSize.
	DropOversize uint64
	// Packets discarded after their configured lifetime elapsed in transit.
	DropExpired uint64
	// Packets discarded while the outgoing link was disabled.
	DropLinkDown uint64
	// Additional packet copies scheduled by simulated duplication.
	DuplicatedPackets uint64
	// Accepted outgoing packets whose payload was changed by simulated corruption.
	CorruptedPackets uint64
	// Writes rejected because the outgoing queue was full or its sender was closed.
	DropPendingQueue uint64
	// Packets accepted by WriteTo, including simulated losses.
	SentPackets uint64
	// Packets accepted into the receive queue.
	RecvPackets uint64
	// Payload bytes accepted by WriteTo.
	SentBytes uint64
	// Payload bytes accepted into the receive queue.
	RecvBytes uint64
	// Largest observed delivery delay.
	MaxDelay time.Duration
	// Packets given an extra delay for reordering.
	Reordered uint64
	// Packets given additional congestion delay from the pending send queue.
	QueueDelayedPackets uint64
	// Packets scheduled for delivery after a non-zero delay.
	DelayedSends uint64
}

Stats is a snapshot of a connection's packet, byte, loss, and delay counters.

type TimedSender

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

TimedSender delivers packets to connections at their scheduled times. Call Close when the sender is no longer needed.

func NewTimedSender

func NewTimedSender() *TimedSender

NewTimedSender creates an unbounded sender. Call Close when finished.

func (*TimedSender) Close added in v1.1.0

func (h *TimedSender) Close() error

Close stops the sender and discards packets that have not yet been delivered. It is safe to call Close more than once.

func (*TimedSender) Len

func (h *TimedSender) Len() int

func (*TimedSender) Less

func (h *TimedSender) Less(i, j int) bool

func (*TimedSender) Pop

func (h *TimedSender) Pop() interface{}

func (*TimedSender) Push

func (h *TimedSender) Push(x interface{})

func (*TimedSender) Send

func (h *TimedSender) Send(conn *LossyConn, packet Packet, delay time.Duration)

Send schedules packet for delivery after delay. Calls made after Close are ignored.

func (*TimedSender) Swap

func (h *TimedSender) Swap(i, j int)

Jump to

Keyboard shortcuts

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