api

package module
v0.55.0 Latest Latest
Warning

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

Go to latest
Published: Oct 3, 2025 License: MIT Imports: 5 Imported by: 2

Documentation

Overview

Package api contains auto-generated interfaces and wrappers for the quic data structures.

This package is intended for those who need to wrappers around quic structures, typically quic.Conn or quic.Stream for testing, intercepting function calls, etc.

Example
package main

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io"
	"log"
	"sync"
	"sync/atomic"

	"github.com/c2FmZQ/quic-api"
)

// myListener is a trivial wrapper around [api.Listener] that increases a
// counter when data is read from a stream on a received connection.
type myListener struct {
	api.Listener
	counter *atomic.Int32
}

func (ln *myListener) Accept(ctx context.Context) (api.Conn, error) {
	conn, err := ln.Listener.Accept(ctx)
	if err != nil {
		return nil, err
	}
	return &myConn{Conn: conn, counter: ln.counter}, nil
}

// myConn is a trivial wrapper around [api.Conn] that increases a
// counter when data is read from a stream on a received connection.
type myConn struct {
	api.Conn
	counter *atomic.Int32
}

func (c *myConn) AcceptStream(ctx context.Context) (api.Stream, error) {
	stream, err := c.Conn.AcceptStream(ctx)
	if err != nil {
		return nil, err
	}
	return &myStream{Stream: stream, counter: c.counter}, nil
}

func (c *myConn) OpenStream() (api.Stream, error) {
	stream, err := c.Conn.OpenStream()
	if err != nil {
		return nil, err
	}
	return &myStream{Stream: stream, counter: c.counter}, nil
}

// myStream is a trivial wrapper around [api.Stream] that increases a
// counter when data is read from a stream on a received connection.
type myStream struct {
	api.Stream
	counter *atomic.Int32
}

func (s *myStream) Read(b []byte) (int, error) {
	n, err := s.Stream.Read(b)
	s.counter.Add(int32(n)) // Count the number of bytes read
	return n, err
}

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	serverReadCounter := new(atomic.Int32)
	clientReadCounter := new(atomic.Int32)

	cert, err := newCert("example.com")
	if err != nil {
		log.Fatalf("newCert: %v", err)
	}

	// Start the server.
	ln, err := api.ListenAddr("localhost:0", &tls.Config{
		Certificates: []tls.Certificate{cert},
		NextProtos:   []string{"foo"},
	}, nil)
	if err != nil {
		log.Fatalf("ListenAddr: %v", err)
	}
	// Here, we replace ln with our own api.Listener implementation
	// which simply increments the counter for every byte read from
	// a stream.
	ln = &myListener{Listener: ln, counter: serverReadCounter}
	go quicServer(ctx, ln)

	pool := x509.NewCertPool()
	pool.AddCert(cert.Leaf)

	// Open a QUIC connection to the server.
	conn, err := api.DialAddr(ctx, ln.Addr().String(), &tls.Config{
		ServerName: "example.com",
		RootCAs:    pool,
		NextProtos: []string{"foo"},
	}, nil)
	if err != nil {
		log.Fatalf("DialAddr: %v", err)
	}
	// We also count the number of bytes read by the client.
	conn = &myConn{Conn: conn, counter: clientReadCounter}

	var wg sync.WaitGroup
	for range 100 {
		wg.Add(1)
		go func() {
			defer wg.Done()
			sendMessage(conn, "Hello World!\n")
		}()
	}
	wg.Wait()

	fmt.Printf("Server Read Counter: %d\n", serverReadCounter.Load())
	fmt.Printf("Client Read Counter: %d\n", clientReadCounter.Load())
}

// sendMessage opens a bidirectional stream, sends one message, and reads the
// answers before closing the stream. It doesn't know anything about the myConn
// implementation.
//
// When stream.Read() is called, the underlying counter is incremented.
func sendMessage(conn api.Conn, message string) {
	stream, err := conn.OpenStream()
	if err != nil {
		log.Fatalf("OpenStream: %v", err)
	}
	defer stream.Close()

	if _, err := stream.Write([]byte(message)); err != nil {
		log.Fatalf("Client Write: %v", err)
	}
	log.Printf("Client sent %q (len=%d)", message, len(message))

	answer := make([]byte, 1024)
	n, err := stream.Read(answer)
	if err != nil && !errors.Is(err, io.EOF) {
		log.Fatalf("Client Read: %v", err)
	}
	log.Printf("Client read %q (len=%d)", answer[:n], n)
}

// quicServer represents an arbitrary QUIC server that uses an [api.Listener] as
// argument. It doesn't know anything about the actual myListener
// implementation.
//
// When stream.Read() is called, the underlying counter is incremented.
func quicServer(ctx context.Context, ln api.Listener) {
	for {
		conn, err := ln.Accept(ctx)
		if err != nil {
			log.Printf("Accept: %v", err)
			return
		}
		go func(ctx context.Context, conn api.Conn) {
			for {
				stream, err := conn.AcceptStream(ctx)
				if err != nil {
					log.Printf("AcceptStream: %v", err)
					return
				}
				go func(stream api.Stream) {
					buf := make([]byte, 1024)
					for {
						n, err := stream.Read(buf)
						if n > 0 {
							if _, err := stream.Write([]byte("ack\n")); err != nil {
								log.Printf("Server Write: %v", err)
								return
							}
						}
						if err != nil {
							if !errors.Is(err, io.EOF) {
								log.Printf("Server Read: %d, %v", n, err)
							}
							break
						}
					}
					if err := stream.Close(); err != nil {
						log.Printf("Server Close: %v", err)
					}
				}(stream)
			}
		}(ctx, conn)
	}
}
Output:

Server Read Counter: 1300
Client Read Counter: 400

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Conn

type Conn interface {
	AcceptStream(context.Context) (Stream, error)
	AcceptUniStream(context.Context) (ReceiveStream, error)
	AddPath(TransportUnwrapper) (Path, error)
	CloseWithError(quic.ApplicationErrorCode, string) error
	ConnectionState() quic.ConnectionState
	ConnectionStats() quic.ConnectionStats
	Context() context.Context
	HandshakeComplete() <-chan struct{}
	LocalAddr() net.Addr
	NextConnection(context.Context) (Conn, error)
	OpenStream() (Stream, error)
	OpenStreamSync(context.Context) (Stream, error)
	OpenUniStream() (SendStream, error)
	OpenUniStreamSync(context.Context) (SendStream, error)
	ReceiveDatagram(context.Context) ([]byte, error)
	RemoteAddr() net.Addr
	SendDatagram([]byte) error
}

Conn is an auto-generated interface for quic.Conn. Use WrapConn to convert a *quic.Conn to a Conn.

func Dial

func Dial(ctx context.Context, p net.PacketConn, addr net.Addr, tc *tls.Config, qc *quic.Config) (conn Conn, err error)

Dial is an auto-generated wrapper for quic.Dial

func DialAddr

func DialAddr(ctx context.Context, s string, tc *tls.Config, qc *quic.Config) (conn Conn, err error)

DialAddr is an auto-generated wrapper for quic.DialAddr

func DialAddrEarly

func DialAddrEarly(ctx context.Context, s string, tc *tls.Config, qc *quic.Config) (conn Conn, err error)

DialAddrEarly is an auto-generated wrapper for quic.DialAddrEarly

func DialEarly

func DialEarly(ctx context.Context, p net.PacketConn, addr net.Addr, tc *tls.Config, qc *quic.Config) (conn Conn, err error)

DialEarly is an auto-generated wrapper for quic.DialEarly

type ConnUnwrapper

type ConnUnwrapper interface {
	Unwrap() *quic.Conn
}

ConnUnwrapper is an auto-generated interface to unwrap a *quic.Conn. The value returned by WrapConn implements this interface.

type EarlyListener

type EarlyListener interface {
	Accept(context.Context) (Conn, error)
	Addr() net.Addr
	Close() error
}

EarlyListener is an auto-generated interface for quic.EarlyListener. Use WrapEarlyListener to convert a *quic.EarlyListener to a EarlyListener.

func ListenAddrEarly

func ListenAddrEarly(s string, tc *tls.Config, qc *quic.Config) (ln EarlyListener, err error)

ListenAddrEarly is an auto-generated wrapper for quic.ListenAddrEarly

func ListenEarly

func ListenEarly(p net.PacketConn, tc *tls.Config, qc *quic.Config) (ln EarlyListener, err error)

ListenEarly is an auto-generated wrapper for quic.ListenEarly

type EarlyListenerUnwrapper

type EarlyListenerUnwrapper interface {
	Unwrap() *quic.EarlyListener
}

EarlyListenerUnwrapper is an auto-generated interface to unwrap a *quic.EarlyListener. The value returned by WrapEarlyListener implements this interface.

type Listener

type Listener interface {
	Accept(context.Context) (Conn, error)
	Addr() net.Addr
	Close() error
}

Listener is an auto-generated interface for quic.Listener. Use WrapListener to convert a *quic.Listener to a Listener.

func Listen

func Listen(p net.PacketConn, tc *tls.Config, qc *quic.Config) (ln Listener, err error)

Listen is an auto-generated wrapper for quic.Listen

func ListenAddr

func ListenAddr(s string, tc *tls.Config, qc *quic.Config) (ln Listener, err error)

ListenAddr is an auto-generated wrapper for quic.ListenAddr

type ListenerUnwrapper

type ListenerUnwrapper interface {
	Unwrap() *quic.Listener
}

ListenerUnwrapper is an auto-generated interface to unwrap a *quic.Listener. The value returned by WrapListener implements this interface.

type Path

type Path interface {
	Close() error
	Probe(context.Context) error
	Switch() error
}

Path is an auto-generated interface for quic.Path. Use WrapPath to convert a *quic.Path to a Path.

type PathUnwrapper

type PathUnwrapper interface {
	Unwrap() *quic.Path
}

PathUnwrapper is an auto-generated interface to unwrap a *quic.Path. The value returned by WrapPath implements this interface.

type ReceiveStream

type ReceiveStream interface {
	CancelRead(quic.StreamErrorCode)
	Read([]byte) (int, error)
	SetReadDeadline(time.Time) error
	StreamID() quic.StreamID
}

ReceiveStream is an auto-generated interface for quic.ReceiveStream. Use WrapReceiveStream to convert a *quic.ReceiveStream to a ReceiveStream.

type ReceiveStreamUnwrapper

type ReceiveStreamUnwrapper interface {
	Unwrap() *quic.ReceiveStream
}

ReceiveStreamUnwrapper is an auto-generated interface to unwrap a *quic.ReceiveStream. The value returned by WrapReceiveStream implements this interface.

type SendStream

type SendStream interface {
	CancelWrite(quic.StreamErrorCode)
	Close() error
	Context() context.Context
	SetReliableBoundary()
	SetWriteDeadline(time.Time) error
	StreamID() quic.StreamID
	Write([]byte) (int, error)
}

SendStream is an auto-generated interface for quic.SendStream. Use WrapSendStream to convert a *quic.SendStream to a SendStream.

type SendStreamUnwrapper

type SendStreamUnwrapper interface {
	Unwrap() *quic.SendStream
}

SendStreamUnwrapper is an auto-generated interface to unwrap a *quic.SendStream. The value returned by WrapSendStream implements this interface.

type Stream

type Stream interface {
	CancelRead(quic.StreamErrorCode)
	CancelWrite(quic.StreamErrorCode)
	Close() error
	Context() context.Context
	Read([]byte) (int, error)
	SetDeadline(time.Time) error
	SetReadDeadline(time.Time) error
	SetWriteDeadline(time.Time) error
	StreamID() quic.StreamID
	Write([]byte) (int, error)
}

Stream is an auto-generated interface for quic.Stream. Use WrapStream to convert a *quic.Stream to a Stream.

type StreamUnwrapper

type StreamUnwrapper interface {
	Unwrap() *quic.Stream
}

StreamUnwrapper is an auto-generated interface to unwrap a *quic.Stream. The value returned by WrapStream implements this interface.

type Transport

type Transport interface {
	Close() error
	Dial(context.Context, net.Addr, *tls.Config, *quic.Config) (Conn, error)
	DialEarly(context.Context, net.Addr, *tls.Config, *quic.Config) (Conn, error)
	Listen(*tls.Config, *quic.Config) (Listener, error)
	ListenEarly(*tls.Config, *quic.Config) (EarlyListener, error)
	ReadNonQUICPacket(context.Context, []byte) (int, net.Addr, error)
	WriteTo([]byte, net.Addr) (int, error)
}

Transport is an auto-generated interface for quic.Transport. Use WrapTransport to convert a *quic.Transport to a Transport.

type TransportUnwrapper

type TransportUnwrapper interface {
	Unwrap() *quic.Transport
}

TransportUnwrapper is an auto-generated interface to unwrap a *quic.Transport. The value returned by WrapTransport implements this interface.

type WrappedConn

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

WrappedConn is an auto-generated wrapper for quic.Conn. It implements the Conn interface.

func WrapConn

func WrapConn(conn *quic.Conn) *WrappedConn

WrapConn converts a quic.Conn to a Conn.

func (*WrappedConn) AcceptStream

func (w *WrappedConn) AcceptStream(ctx context.Context) (stream Stream, err error)

func (*WrappedConn) AcceptUniStream

func (w *WrappedConn) AcceptUniStream(ctx context.Context) (stream ReceiveStream, err error)

func (*WrappedConn) AddPath

func (w *WrappedConn) AddPath(t TransportUnwrapper) (p Path, err error)

func (*WrappedConn) CloseWithError

func (w *WrappedConn) CloseWithError(code quic.ApplicationErrorCode, s string) error

func (*WrappedConn) ConnectionState

func (w *WrappedConn) ConnectionState() quic.ConnectionState

func (*WrappedConn) ConnectionStats added in v0.55.0

func (w *WrappedConn) ConnectionStats() quic.ConnectionStats

func (*WrappedConn) Context

func (w *WrappedConn) Context() context.Context

func (*WrappedConn) HandshakeComplete

func (w *WrappedConn) HandshakeComplete() <-chan struct{}

func (*WrappedConn) LocalAddr

func (w *WrappedConn) LocalAddr() net.Addr

func (*WrappedConn) NextConnection

func (w *WrappedConn) NextConnection(ctx context.Context) (conn Conn, err error)

func (*WrappedConn) OpenStream

func (w *WrappedConn) OpenStream() (stream Stream, err error)

func (*WrappedConn) OpenStreamSync

func (w *WrappedConn) OpenStreamSync(ctx context.Context) (stream Stream, err error)

func (*WrappedConn) OpenUniStream

func (w *WrappedConn) OpenUniStream() (stream SendStream, err error)

func (*WrappedConn) OpenUniStreamSync

func (w *WrappedConn) OpenUniStreamSync(ctx context.Context) (stream SendStream, err error)

func (*WrappedConn) ReceiveDatagram

func (w *WrappedConn) ReceiveDatagram(ctx context.Context) ([]byte, error)

func (*WrappedConn) RemoteAddr

func (w *WrappedConn) RemoteAddr() net.Addr

func (*WrappedConn) SendDatagram

func (w *WrappedConn) SendDatagram(b []byte) error

func (*WrappedConn) Unwrap

func (w *WrappedConn) Unwrap() *quic.Conn

Unwrap returns the underlying *quic.Conn.

type WrappedEarlyListener

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

WrappedEarlyListener is an auto-generated wrapper for quic.EarlyListener. It implements the EarlyListener interface.

func WrapEarlyListener

func WrapEarlyListener(ln *quic.EarlyListener) *WrappedEarlyListener

WrapEarlyListener converts a quic.EarlyListener to a EarlyListener.

func (*WrappedEarlyListener) Accept

func (w *WrappedEarlyListener) Accept(ctx context.Context) (conn Conn, err error)

func (*WrappedEarlyListener) Addr

func (w *WrappedEarlyListener) Addr() net.Addr

func (*WrappedEarlyListener) Close

func (w *WrappedEarlyListener) Close() error

func (*WrappedEarlyListener) Unwrap

func (w *WrappedEarlyListener) Unwrap() *quic.EarlyListener

Unwrap returns the underlying *quic.EarlyListener.

type WrappedListener

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

WrappedListener is an auto-generated wrapper for quic.Listener. It implements the Listener interface.

func WrapListener

func WrapListener(ln *quic.Listener) *WrappedListener

WrapListener converts a quic.Listener to a Listener.

func (*WrappedListener) Accept

func (w *WrappedListener) Accept(ctx context.Context) (conn Conn, err error)

func (*WrappedListener) Addr

func (w *WrappedListener) Addr() net.Addr

func (*WrappedListener) Close

func (w *WrappedListener) Close() error

func (*WrappedListener) Unwrap

func (w *WrappedListener) Unwrap() *quic.Listener

Unwrap returns the underlying *quic.Listener.

type WrappedPath

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

WrappedPath is an auto-generated wrapper for quic.Path. It implements the Path interface.

func WrapPath

func WrapPath(p *quic.Path) *WrappedPath

WrapPath converts a quic.Path to a Path.

func (*WrappedPath) Close

func (w *WrappedPath) Close() error

func (*WrappedPath) Probe

func (w *WrappedPath) Probe(ctx context.Context) error

func (*WrappedPath) Switch

func (w *WrappedPath) Switch() error

func (*WrappedPath) Unwrap

func (w *WrappedPath) Unwrap() *quic.Path

Unwrap returns the underlying *quic.Path.

type WrappedReceiveStream

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

WrappedReceiveStream is an auto-generated wrapper for quic.ReceiveStream. It implements the ReceiveStream interface.

func WrapReceiveStream

func WrapReceiveStream(stream *quic.ReceiveStream) *WrappedReceiveStream

WrapReceiveStream converts a quic.ReceiveStream to a ReceiveStream.

func (*WrappedReceiveStream) CancelRead

func (w *WrappedReceiveStream) CancelRead(code quic.StreamErrorCode)

func (*WrappedReceiveStream) Read

func (w *WrappedReceiveStream) Read(b []byte) (int, error)

func (*WrappedReceiveStream) SetReadDeadline

func (w *WrappedReceiveStream) SetReadDeadline(t time.Time) error

func (*WrappedReceiveStream) StreamID

func (w *WrappedReceiveStream) StreamID() quic.StreamID

func (*WrappedReceiveStream) Unwrap

func (w *WrappedReceiveStream) Unwrap() *quic.ReceiveStream

Unwrap returns the underlying *quic.ReceiveStream.

type WrappedSendStream

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

WrappedSendStream is an auto-generated wrapper for quic.SendStream. It implements the SendStream interface.

func WrapSendStream

func WrapSendStream(stream *quic.SendStream) *WrappedSendStream

WrapSendStream converts a quic.SendStream to a SendStream.

func (*WrappedSendStream) CancelWrite

func (w *WrappedSendStream) CancelWrite(code quic.StreamErrorCode)

func (*WrappedSendStream) Close

func (w *WrappedSendStream) Close() error

func (*WrappedSendStream) Context

func (w *WrappedSendStream) Context() context.Context

func (*WrappedSendStream) SetReliableBoundary added in v0.54.0

func (w *WrappedSendStream) SetReliableBoundary()

func (*WrappedSendStream) SetWriteDeadline

func (w *WrappedSendStream) SetWriteDeadline(t time.Time) error

func (*WrappedSendStream) StreamID

func (w *WrappedSendStream) StreamID() quic.StreamID

func (*WrappedSendStream) Unwrap

func (w *WrappedSendStream) Unwrap() *quic.SendStream

Unwrap returns the underlying *quic.SendStream.

func (*WrappedSendStream) Write

func (w *WrappedSendStream) Write(b []byte) (int, error)

type WrappedStream

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

WrappedStream is an auto-generated wrapper for quic.Stream. It implements the Stream interface.

func WrapStream

func WrapStream(stream *quic.Stream) *WrappedStream

WrapStream converts a quic.Stream to a Stream.

func (*WrappedStream) CancelRead

func (w *WrappedStream) CancelRead(code quic.StreamErrorCode)

func (*WrappedStream) CancelWrite

func (w *WrappedStream) CancelWrite(code quic.StreamErrorCode)

func (*WrappedStream) Close

func (w *WrappedStream) Close() error

func (*WrappedStream) Context

func (w *WrappedStream) Context() context.Context

func (*WrappedStream) Read

func (w *WrappedStream) Read(b []byte) (int, error)

func (*WrappedStream) SetDeadline

func (w *WrappedStream) SetDeadline(t time.Time) error

func (*WrappedStream) SetReadDeadline

func (w *WrappedStream) SetReadDeadline(t time.Time) error

func (*WrappedStream) SetWriteDeadline

func (w *WrappedStream) SetWriteDeadline(t time.Time) error

func (*WrappedStream) StreamID

func (w *WrappedStream) StreamID() quic.StreamID

func (*WrappedStream) Unwrap

func (w *WrappedStream) Unwrap() *quic.Stream

Unwrap returns the underlying *quic.Stream.

func (*WrappedStream) Write

func (w *WrappedStream) Write(b []byte) (int, error)

type WrappedTransport

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

WrappedTransport is an auto-generated wrapper for quic.Transport. It implements the Transport interface.

func WrapTransport

func WrapTransport(t *quic.Transport) *WrappedTransport

WrapTransport converts a quic.Transport to a Transport.

func (*WrappedTransport) Close

func (w *WrappedTransport) Close() error

func (*WrappedTransport) Dial

func (w *WrappedTransport) Dial(ctx context.Context, addr net.Addr, tc *tls.Config, qc *quic.Config) (conn Conn, err error)

func (*WrappedTransport) DialEarly

func (w *WrappedTransport) DialEarly(ctx context.Context, addr net.Addr, tc *tls.Config, qc *quic.Config) (conn Conn, err error)

func (*WrappedTransport) Listen

func (w *WrappedTransport) Listen(tc *tls.Config, qc *quic.Config) (ln Listener, err error)

func (*WrappedTransport) ListenEarly

func (w *WrappedTransport) ListenEarly(tc *tls.Config, qc *quic.Config) (ln EarlyListener, err error)

func (*WrappedTransport) ReadNonQUICPacket

func (w *WrappedTransport) ReadNonQUICPacket(ctx context.Context, b []byte) (int, net.Addr, error)

func (*WrappedTransport) Unwrap

func (w *WrappedTransport) Unwrap() *quic.Transport

Unwrap returns the underlying *quic.Transport.

func (*WrappedTransport) WriteTo

func (w *WrappedTransport) WriteTo(b []byte, addr net.Addr) (int, error)

Directories

Path Synopsis
internal
gen command

Jump to

Keyboard shortcuts

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