Yamux

repository·master·Indexed 25 days ago

https://github.com/hashicorp/yamux

A Golang library for multiplexing multiple logical streams over a single reliable underlying connection, such as TCP or Unix domain sockets. Yamux provides bi-directional streams, flow control with back-pressure, and keep-alives to support thousands of logical streams with low overhead. It includes a framing layer with specific message types (Data, Window Update, Ping, Go Away) and flags (SYN, ACK, FIN, RST) to manage session and stream lifecycles.

Tokens
4.2K
Snippets
4
Records
40
Agent score
82%

What's inside yamux

  1. Overview of Yamux

    master

    Yamux (Yet another Multiplexer) is a Golang library that provides stream-oriented multiplexing over reliable, ordered underlying connections like TCP or Unix domain sockets. It is inspired by SPDY but is not interoperable with it.

    Key features include:

    • Bi-directional streams: Streams can be opened by either the client or the server, supporting NAT traversal and server-side push.
    • Flow control: Implements back-pressure to prevent overwhelming a receiver and avoids resource starvation.
    • Keep Alives: Enables persistent connections, which is useful for maintaining connections through load balancers.
    • Efficiency: Designed to support thousands of logical streams with low overhead.
  2. Open and Close Yamux Streams

    master

    Opening a Stream

    1. The initiator sends an initial Data or Window Update frame with a new StreamID and the SYN flag set.
    2. The receiver responds with a Data or Window Update frame containing the ACK flag to accept, or the RST flag to reject.
    3. Note: Because the underlying transport is reliable, data can be sent immediately after the SYN frame without waiting for the ACK. Clients must be prepared to handle errors if a RST is received after data has already been sent.

    Closing a Stream

    • Half-close: Send a Data or Window Update frame with the FIN flag. The stream is fully closed once both sides have performed a half-close.
    • Hard close: Send a frame with the RST flag to terminate the stream immediately due to an error.
  3. Yamux Flow Control and Window Sizes

    master

    Yamux implements per-stream flow control:

    • Initial Window: Each new stream starts with a 256KB window size.
    • Session Window: There is no window size for the session itself.
    • Updating Windows: Send Window Update frames regularly to prevent streams from stalling. Both sides can immediately send a Window Update during the SYN/ACK handshake to negotiate a larger window.
    • Tracking: Both sides should only track the number of bytes sent in Data frames, as only these contribute to the window size.
  4. Manage multiplexed connections with Session

    master

    The Session struct wraps a reliable ordered connection (implementing io.ReadWriteCloser) and multiplexes it into multiple independent streams. It provides methods to open new streams, accept incoming streams, and manage the session lifecycle.

    Key capabilities:

    • Open streams: Create new outgoing streams as net.Conn objects.
    • Accept streams: Block and wait for incoming streams from the remote peer.
    • Lifecycle management: Close the entire session or signal a GoAway to prevent new connections without immediately dropping the underlying connection.
    • Health checks: Use Ping() to measure RTT or rely on configured keep-alive intervals.
  5. Use Yamux to establish a server-side session

    master

    To use Yamux as a server, accept an underlying connection (e.g., via listener.Accept()) and wrap it using yamux.Server(conn, config). You can then use session.Accept() to wait for and accept incoming streams opened by the client. The accepted stream implements the net.Conn interface.

    // Accept a TCP connection
    conn, err := listener.Accept()
    if err != nil {
        panic(err)
    }
    
    // Setup server side of yamux
    session, err := yamux.Server(conn, nil)
    if err != nil {
        panic(err)
    }
    
    // Accept a stream
    stream, err := session.Accept()
    if err != nil {
        panic(err)
    }
    
    // Listen for a message
    buf := make([]byte, 4)
    stream.Read(buf)
  6. Use Yamux to establish a client-side session

    master

    To use Yamux as a client, first establish a reliable connection (e.g., via net.Dial). Then, use yamux.Client(conn, config) to wrap that connection in a Yamux session. Once the session is established, you can call session.Open() to create new bi-directional streams. The resulting stream implements the net.Conn interface.

    // Get a TCP connection
    conn, err := net.Dial("tcp", "example.com:80")
    if err != nil {
        panic(err)
    }
    
    // Setup client side of yamux
    session, err := yamux.Client(conn, nil)
    if err != nil {
        panic(err)
    }
    
    // Open a new stream
    stream, err := session.Open()
    if err != nil {
        panic(err)
    }
    
    // Stream implements net.Conn
    stream.Write([]byte("ping"))
  7. Yamux Frame Flags

    master

    The Flags field provides additional context for the message type:

    • 0x1 SYN: Signals the start of a new stream. Used with Data, Window Update, or Ping (to indicate outbound).
    • 0x2 ACK: Acknowledges a new stream. Used with Data, Window Update, or Ping (to indicate response).
    • 0x4 FIN: Performs a half-close of a stream. Used with Data or Window Update.
    • 0x8 RST: Immediately resets/closes a stream. Used with Data or Window Update.
  8. Yamux Frame Format Specification

    master

    Yamux uses a message framing layer over a streaming connection to multiplex multiple logical streams. Each frame has a 12-byte header encoded in network order (big endian).

    Frame Header Structure:
    * Version (8 bits)
    * Type (8 bits)
    * Flags (16 bits)
    * StreamID (32 bits)
    * Length (32 bits)
  9. Yamux Message Types

    master

    The Type field determines the purpose of the frame:

    • 0x0 Data: Transmits payload bytes. Length may be zero depending on flags.
    • 0x1 Window Update: Updates the sender's receive window size for per-session flow control.
    • 0x2 Ping: Used for RTT measurement, heartbeats, and TCP keep-alives.
    • 0x3 Go Away: Signals session termination.
  10. Yamux Stream ID Rules

    master

    The StreamID identifies the logical stream:

    • Client side: Must use odd IDs.
    • Server side: Must use even IDs.
    • Session-level messages: Both Ping and Go Away messages must use StreamID 0.
    • Reserved: ID 0 is reserved to represent the session.
  11. Yamux Length Field Semantics

    master

    The meaning of the Length field varies by Type:

    • Data: Length of the bytes following the header.
    • Window Update: A delta update to the window size.
    • Ping: An opaque value that is echoed back.
    • Go Away: An error code.