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 "golang.org/x/net/quic"All blocking operations may be canceled using a context.Context.
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
)// 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)// 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 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 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 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 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 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 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 is an application protocol error code indicating why a stream is being closed
type StreamErrorCode uint64
func (e StreamErrorCode) Error() stringimport (
"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])
}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
}