or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

bpf.mdcontext-ctxhttp.mdcontext.mddict.mddns-dnsmessage.mdhtml-atom.mdhtml-charset.mdhtml.mdhttp-httpguts.mdhttp-httpproxy.mdhttp2-h2c.mdhttp2-hpack.mdhttp2.mdicmp.mdidna.mdindex.mdipv4.mdipv6.mdnettest.mdnetutil.mdproxy.mdpublicsuffix.mdquic-qlog.mdquic.mdtrace.mdwebdav.mdwebsocket.mdxsrftoken.md
tile.json

quic.mddocs/

QUIC Protocol

Package quic implements the QUIC protocol.

Note: This package is a work in progress. It is not ready for production usage. Its API is subject to change without notice. Most users will use it indirectly through an HTTP/3 implementation.

Import

import "golang.org/x/net/quic"

Overview

  • Endpoint: Sends and receives traffic on a network address
  • Conn: A QUIC connection
  • Stream: An ordered, reliable byte stream

All blocking operations may be canceled using a context.Context.

Constants

const (
    QLogLevelFrame    = slog.Level(-6) // Per-frame information
    QLogLevelPacket   = slog.Level(-4) // Per-packet events
    QLogLevelConn     = slog.Level(-2) // Connection lifetime events
    QLogLevelEndpoint = slog.Level(0)  // Per-connection events
)

Functions

// Listen listens on a local network address
func Listen(network, address string, listenConfig *Config) (*Endpoint, error)

// NewEndpoint creates an endpoint using a net.PacketConn
func NewEndpoint(conn net.PacketConn, config *Config) (*Endpoint, error)

Types

Config

// Config contains configuration for an Endpoint
type Config struct {
    TLSConfig                    *tls.Config
    MaxBidiRemoteStreams         int64         // Maximum bidirectional streams peer may create
    MaxUniRemoteStreams          int64         // Maximum unidirectional streams peer may create
    MaxStreamReadBufferSize      int64         // Maximum stream read buffer size
    MaxStreamWriteBufferSize     int64         // Maximum stream write buffer size
    MaxConnReadBufferSize        int64         // Maximum connection read buffer size
    QLogLogger                   *slog.Logger  // Logger for qlog events
    RequireAddressValidation     bool          // Require address validation for new connections
    HandshakeTimeout             time.Duration // Handshake timeout
    MaxIdleTimeout               time.Duration // Maximum idle timeout
    KeepAlivePeriod              time.Duration // Keep-alive period
    // Has unexported fields
}

Endpoint

// Endpoint sends and receives QUIC traffic on a network address
type Endpoint struct {
    // Has unexported fields
}

func (e *Endpoint) Dial(ctx context.Context, network, address string) (*Conn, error)
func (e *Endpoint) Accept(ctx context.Context) (*Conn, error)
func (e *Endpoint) LocalAddr() net.Addr
func (e *Endpoint) Close(ctx context.Context) error

Conn

// Conn is a QUIC connection
type Conn struct {
    // Has unexported fields
}

func (c *Conn) AcceptStream(ctx context.Context) (*Stream, error)
func (c *Conn) NewStream(ctx context.Context) (*Stream, error)
func (c *Conn) NewSendOnlyStream(ctx context.Context) (*SendStream, error)
func (c *Conn) NewReceiveOnlyStream(ctx context.Context) (*ReceiveStream, error)
func (c *Conn) Close() error
func (c *Conn) CloseWithError(code uint64, reason string) error
func (c *Conn) LocalAddr() net.Addr
func (c *Conn) RemoteAddr() net.Addr
func (c *Conn) SendDatagram(ctx context.Context, b []byte) error
func (c *Conn) ReceiveDatagram(ctx context.Context) ([]byte, error)
func (c *Conn) Wait(ctx context.Context) error

Stream

// Stream is a QUIC stream
type Stream struct {
    // Has unexported fields
}

func (s *Stream) Read(b []byte) (n int, err error)
func (s *Stream) Write(b []byte) (n int, err error)
func (s *Stream) Close() error
func (s *Stream) CloseRead() error
func (s *Stream) CloseWrite() error
func (s *Stream) Reset(code uint64) error
func (s *Stream) StopWrite(code uint64) error
func (s *Stream) SetReadContext(ctx context.Context)
func (s *Stream) SetWriteContext(ctx context.Context)
func (s *Stream) ID() int64

SendStream

// SendStream is a send-only QUIC stream
type SendStream struct {
    // Has unexported fields
}

func (s *SendStream) Write(b []byte) (n int, err error)
func (s *SendStream) Close() error
func (s *SendStream) Reset(code uint64) error
func (s *SendStream) SetWriteContext(ctx context.Context)
func (s *SendStream) ID() int64

ReceiveStream

// ReceiveStream is a receive-only QUIC stream
type ReceiveStream struct {
    // Has unexported fields
}

func (s *ReceiveStream) Read(b []byte) (n int, err error)
func (s *ReceiveStream) CloseRead() error
func (s *ReceiveStream) StopWrite(code uint64) error
func (s *ReceiveStream) SetReadContext(ctx context.Context)
func (s *ReceiveStream) ID() int64

ApplicationError

// ApplicationError is an application protocol error code
type ApplicationError struct {
    Code   uint64
    Reason string
}

func (e *ApplicationError) Error() string
func (e *ApplicationError) Is(err error) bool

StreamErrorCode

// StreamErrorCode is an application protocol error code indicating why a stream is being closed
type StreamErrorCode uint64

func (e StreamErrorCode) Error() string

Usage Examples

QUIC Server

import (
    "context"
    "crypto/tls"
    "golang.org/x/net/quic"
)

func startQUICServer() error {
    tlsConfig := &tls.Config{
        Certificates: []tls.Certificate{cert},
    }

    config := &quic.Config{
        TLSConfig: tlsConfig,
    }

    endpoint, err := quic.Listen("udp", ":4433", config)
    if err != nil {
        return err
    }
    defer endpoint.Close(context.Background())

    for {
        conn, err := endpoint.Accept(context.Background())
        if err != nil {
            return err
        }

        go handleConnection(conn)
    }
}

func handleConnection(conn *quic.Conn) {
    defer conn.Close()

    for {
        stream, err := conn.AcceptStream(context.Background())
        if err != nil {
            return
        }

        go handleStream(stream)
    }
}

func handleStream(stream *quic.Stream) {
    defer stream.Close()

    buf := make([]byte, 4096)
    n, err := stream.Read(buf)
    if err != nil {
        return
    }

    stream.Write(buf[:n])
}

QUIC Client

func connectQUICClient() error {
    tlsConfig := &tls.Config{
        InsecureSkipVerify: true, // For testing only
    }

    config := &quic.Config{
        TLSConfig: tlsConfig,
    }

    endpoint, err := quic.Listen("udp", ":0", nil)
    if err != nil {
        return err
    }
    defer endpoint.Close(context.Background())

    conn, err := endpoint.Dial(context.Background(), "udp", "localhost:4433")
    if err != nil {
        return err
    }
    defer conn.Close()

    stream, err := conn.NewStream(context.Background())
    if err != nil {
        return err
    }
    defer stream.Close()

    // Send data
    _, err = stream.Write([]byte("Hello, QUIC!"))
    if err != nil {
        return err
    }

    // Read response
    buf := make([]byte, 4096)
    n, err := stream.Read(buf)
    if err != nil {
        return err
    }

    fmt.Printf("Received: %s\n", buf[:n])
    return nil
}