Skip to main content

Overview

UDP Mux allows multiple ICE connections to share a single UDP port by demultiplexing packets based on the username fragment (ufrag) from STUN messages. This enables efficient port usage and is particularly useful when you need to handle multiple concurrent WebRTC connections.

UDPMux Interface

The UDPMux interface defines the contract for UDP multiplexing implementations.
type UDPMux interface {
    io.Closer
    GetConn(ufrag string, addr net.Addr) (net.PacketConn, error)
    RemoveConnByUfrag(ufrag string)
    GetListenAddresses() []net.Addr
}

Methods

GetConn
func(ufrag string, addr net.Addr) (net.PacketConn, error)
Returns a PacketConn for the given username fragment and address. Creates a new connection if one doesn’t exist for the specified ufrag.Parameters:
  • ufrag - The username fragment from the ICE credentials
  • addr - The network address to bind to
Returns: A net.PacketConn or an error if the connection cannot be created
RemoveConnByUfrag
func(ufrag string)
Stops and removes the muxed packet connection associated with the given username fragment.Parameters:
  • ufrag - The username fragment identifying the connection to remove
GetListenAddresses
func() []net.Addr
Returns the list of addresses that this mux is listening on.Returns: A slice of net.Addr representing all listening addresses
Close
func() error
Closes the mux and all associated connections. No further connections can be created after closing.Returns: An error if the close operation fails

UDPMuxDefault

UDPMuxDefault is the default implementation of the UDPMux interface.

Creating a UDPMuxDefault

func NewUDPMuxDefault(params UDPMuxParams) *UDPMuxDefault
Creates a new UDP mux with the specified parameters.

UDPMuxParams

Logger
logging.LeveledLogger
Logger instance for the mux. If nil, a default logger will be created.
UDPConn
net.PacketConn
required
The UDP connection to multiplex. This should be bound to a specific address.
Net
transport.Net
Network transport interface. Required when the UDPConn binds to an unspecified address.

Example: Basic UDP Mux

package main

import (
    "net"
    "github.com/pion/ice/v4"
)

func main() {
    // Create a UDP connection
    udpAddr := &net.UDPAddr{
        IP:   net.ParseIP("0.0.0.0"),
        Port: 8443,
    }
    
    conn, err := net.ListenUDP("udp", udpAddr)
    if err != nil {
        panic(err)
    }
    
    // Create UDP mux
    mux := ice.NewUDPMuxDefault(ice.UDPMuxParams{
        UDPConn: conn,
    })
    defer mux.Close()
    
    // Get a connection for a specific ufrag
    packetConn, err := mux.GetConn("myufrag", conn.LocalAddr())
    if err != nil {
        panic(err)
    }
    
    // Use packetConn for ICE agent...
}
When using an unspecified address (0.0.0.0 or ::), the mux will automatically detect all local interfaces. However, it’s recommended to use NewMultiUDPMuxFromPort instead for better control.

MultiUDPMuxDefault

MultiUDPMuxDefault allows multiple UDPMux instances to be used together, enabling listening on multiple ports or addresses simultaneously.

Creating a MultiUDPMuxDefault

func NewMultiUDPMuxDefault(muxes ...UDPMux) *MultiUDPMuxDefault
Creates a multi-mux from existing UDPMux instances.
func NewMultiUDPMuxFromPort(port int, opts ...UDPMuxFromPortOption) (*MultiUDPMuxDefault, error)
Creates a multi-mux that listens on all network interfaces on the specified port.

Configuration Options

UDPMuxFromPortWithInterfaceFilter
func(string) bool
Filter to determine which network interfaces should be used.
ice.UDPMuxFromPortWithInterfaceFilter(func(iface string) bool {
    return iface != "docker0" // Exclude docker interface
})
UDPMuxFromPortWithIPFilter
func(net.IP) bool
Filter to determine which IP addresses should be used.
ice.UDPMuxFromPortWithIPFilter(func(ip net.IP) bool {
    return !ip.IsLoopback() // Exclude loopback addresses
})
UDPMuxFromPortWithNetworks
...NetworkType
Specify which network types to use (IPv4, IPv6, or both).
ice.UDPMuxFromPortWithNetworks(ice.NetworkTypeUDP4)
UDPMuxFromPortWithReadBufferSize
int
Set the UDP connection read buffer size in bytes.
ice.UDPMuxFromPortWithReadBufferSize(8 * 1024 * 1024) // 8MB
UDPMuxFromPortWithWriteBufferSize
int
Set the UDP connection write buffer size in bytes.
ice.UDPMuxFromPortWithWriteBufferSize(8 * 1024 * 1024) // 8MB
UDPMuxFromPortWithLogger
logging.LeveledLogger
Set a custom logger for the mux.
UDPMuxFromPortWithLoopback
bool
Include loopback interfaces in the mux.
ice.UDPMuxFromPortWithLoopback()
UDPMuxFromPortWithNet
transport.Net
Set a custom network transport implementation.

Example: Multi-Interface UDP Mux

package main

import (
    "github.com/pion/ice/v4"
)

func main() {
    // Listen on all interfaces on port 8443
    mux, err := ice.NewMultiUDPMuxFromPort(8443)
    if err != nil {
        panic(err)
    }
    defer mux.Close()
    
    // Get all listening addresses
    addrs := mux.GetListenAddresses()
    for _, addr := range addrs {
        println("Listening on:", addr.String())
    }
}

Port Sharing Concepts

How It Works

  1. Packet Demultiplexing: When a packet arrives on the shared UDP port, the mux examines it to determine which connection it belongs to.
  2. STUN Username: For STUN packets, the mux extracts the username attribute and uses the first part (before the colon) as the ufrag to route the packet.
  3. Address Mapping: After the first STUN packet, the mux remembers the remote address and can route subsequent packets (including media) based on the source address.
  4. Connection Lifecycle: Each muxed connection is independent and can be closed without affecting others sharing the same port.

Benefits

  • Reduced Port Usage: Handle multiple WebRTC connections on a single UDP port
  • NAT Traversal: Simplified firewall configuration with fewer ports to open
  • Scalability: Better resource utilization for applications with many concurrent connections
  • IPv4 and IPv6: Separate connection tracking for IPv4 and IPv6 traffic

Limitations

  • The first packet from each remote peer must be a STUN message with a USERNAME attribute
  • Each ufrag should be unique across all connections using the mux
  • Performance may be impacted with very high numbers of concurrent connections (thousands)

Best Practices

  1. Use Specific Addresses: When possible, bind to specific IP addresses rather than 0.0.0.0 for better security and predictability.
  2. Buffer Sizes: For high-throughput applications, configure appropriate read and write buffer sizes:
    mux, _ := ice.NewMultiUDPMuxFromPort(
        8443,
        ice.UDPMuxFromPortWithReadBufferSize(8 * 1024 * 1024),
        ice.UDPMuxFromPortWithWriteBufferSize(8 * 1024 * 1024),
    )
    
  3. Cleanup: Always defer Close() to ensure proper cleanup of resources:
    mux := ice.NewUDPMuxDefault(params)
    defer mux.Close()
    
  4. Interface Filtering: In containerized environments, filter out virtual interfaces:
    ice.UDPMuxFromPortWithInterfaceFilter(func(iface string) bool {
        return !strings.HasPrefix(iface, "veth")
    })
    

Build docs developers (and LLMs) love