mirror of
https://github.com/cloudflare/cloudflared
synced 2026-06-08 13:33:07 +00:00
52519f67e8
The bump of the QUIC library introduces a cyclic dependency between the connection and quic modules hence it is necessary to break this coupling. Right now, the connection module depends on the quic module for the datagram v2/v3 and to which a QUIC connection (currently an interface) is passed. As it is there is no issue however, under the hood, interface is a wrapper around an UDP connection and a QUIC connection meaning this type must be exposed to the quic module since the QUIC Connection will no longer be a interface but a struct. Given the above, these changes introduce an interface, QUICConnection, with the surface used today in cloudflared and a struct, ConnWithCloser, that implements said interface within the quic module. Closes TUN-10563
106 lines
3.2 KiB
Go
106 lines
3.2 KiB
Go
package quic
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"net"
|
|
|
|
"github.com/quic-go/quic-go"
|
|
)
|
|
|
|
// QUICConnection defines the subset of [quic.Connection] methods used by cloudflared.
|
|
// Consumers should accept this interface; producers should return [*ConnWithCloser].
|
|
type QUICConnection interface {
|
|
AcceptStream(ctx context.Context) (quic.Stream, error)
|
|
OpenStream() (quic.Stream, error)
|
|
OpenStreamSync(ctx context.Context) (quic.Stream, error)
|
|
CloseWithError(code quic.ApplicationErrorCode, reason string) error
|
|
Context() context.Context
|
|
SendDatagram(payload []byte) error
|
|
ReceiveDatagram(ctx context.Context) ([]byte, error)
|
|
LocalAddr() net.Addr
|
|
RemoteAddr() net.Addr
|
|
ConnectionState() quic.ConnectionState
|
|
}
|
|
|
|
// Compile-time assertion that *ConnWithCloser implements QUICConnection.
|
|
var _ QUICConnection = (*ConnWithCloser)(nil)
|
|
|
|
var (
|
|
// error returned when the [NewConnWithCloser] is called with a nil conn argument
|
|
ErrNilQuicConnection = errors.New("the provided quic connection is nil")
|
|
// error returned when the [NewConnWithCloser] is called with a nil closer argument
|
|
ErrNilCloser = errors.New("the provided closer is nil")
|
|
)
|
|
|
|
// ConnWithCloser wraps a [quic.Connection] and an [io.Closer] (typically the
|
|
// underlying [*net.UDPConn]). When [CloseWithError] is called the QUIC
|
|
// connection is closed first, then the closer is closed deterministically.
|
|
//
|
|
// A nil conn is only safe for [CloseWithError] (used in tests). All other
|
|
// delegated methods will panic on a nil conn.
|
|
type ConnWithCloser struct {
|
|
conn quic.Connection
|
|
closer io.Closer
|
|
}
|
|
|
|
// NewQUICConnection returns a [*ConnWithCloser] that will close closer after
|
|
// the QUIC connection is closed.
|
|
func NewQUICConnection(conn quic.Connection, closer io.Closer) (*ConnWithCloser, error) {
|
|
if conn == nil {
|
|
return nil, ErrNilQuicConnection
|
|
}
|
|
|
|
if closer == nil {
|
|
return nil, ErrNilCloser
|
|
}
|
|
return &ConnWithCloser{conn: conn, closer: closer}, nil
|
|
}
|
|
|
|
// CloseWithError closes the QUIC connection and then closes the underlying
|
|
// [io.Closer]. If both operations return errors, the errors are joined so that
|
|
// the closer error is no longer silently discarded.
|
|
func (c *ConnWithCloser) CloseWithError(code quic.ApplicationErrorCode, reason string) error {
|
|
connErr := c.conn.CloseWithError(code, reason)
|
|
closerErr := c.closer.Close()
|
|
|
|
return errors.Join(connErr, closerErr)
|
|
}
|
|
|
|
func (c *ConnWithCloser) AcceptStream(ctx context.Context) (quic.Stream, error) {
|
|
return c.conn.AcceptStream(ctx)
|
|
}
|
|
|
|
func (c *ConnWithCloser) OpenStream() (quic.Stream, error) {
|
|
return c.conn.OpenStream()
|
|
}
|
|
|
|
func (c *ConnWithCloser) OpenStreamSync(ctx context.Context) (quic.Stream, error) {
|
|
return c.conn.OpenStreamSync(ctx)
|
|
}
|
|
|
|
func (c *ConnWithCloser) Context() context.Context {
|
|
return c.conn.Context()
|
|
}
|
|
|
|
func (c *ConnWithCloser) SendDatagram(payload []byte) error {
|
|
return c.conn.SendDatagram(payload)
|
|
}
|
|
|
|
func (c *ConnWithCloser) ReceiveDatagram(ctx context.Context) ([]byte, error) {
|
|
return c.conn.ReceiveDatagram(ctx)
|
|
}
|
|
|
|
func (c *ConnWithCloser) LocalAddr() net.Addr {
|
|
return c.conn.LocalAddr()
|
|
}
|
|
|
|
func (c *ConnWithCloser) RemoteAddr() net.Addr {
|
|
return c.conn.RemoteAddr()
|
|
}
|
|
|
|
func (c *ConnWithCloser) ConnectionState() quic.ConnectionState {
|
|
return c.conn.ConnectionState()
|
|
}
|