Files
João Oliveirinha 1ab229d1dd TUN-10738: Propagate edge registration errors over QUIC and fix supervisor error classification
QUIC previously replaced control-stream registration failures with generic
service errors, preventing the supervisor from identifying edge responses such
as EDUPCONN and retryable registration failures. This could repeatedly select
the same edge address or terminate initial registration unexpectedly.

Preserve underlying causes through QUIC service wrappers, including failures
opening the control stream, while returning context cancellation directly.
Represent duplicate registration with a sentinel and use errors.Is and
errors.AsType to classify wrapped errors consistently.

Keep registration permanence available to the supervisor, rotate edge
addresses after EDUPCONN, and classify QUIC dial errors before nested idle
timeouts so connectivity retries can still trigger protocol fallback. Remove
duplicate connection-error logging and suppress expected shutdown noise.

Add coverage for duplicate registration mapping, QUIC error propagation,
cancellation, startup retry policy, edge-address rotation, and wrapped QUIC
dial timeouts.
2026-09-08 14:07:10 -07:00

97 lines
1.8 KiB
Go

package connection
import (
"errors"
"fmt"
tunnelpogs "github.com/cloudflare/cloudflared/tunnelrpc/pogs"
)
const (
DuplicateConnectionError = "EDUPCONN"
)
var ErrDuplicateConnection = errors.New("already connected to this server, trying another address")
// Dial to edge server with quic failed
type EdgeQuicDialError struct {
Cause error
}
func (e *EdgeQuicDialError) Error() string {
return "failed to dial to edge with quic: " + e.Cause.Error()
}
func (e *EdgeQuicDialError) Unwrap() error {
return e.Cause
}
// RegisterTunnel error from server
type ServerRegisterTunnelError struct {
Cause error
Permanent bool
}
func (e ServerRegisterTunnelError) Error() string {
return e.Cause.Error()
}
func (e ServerRegisterTunnelError) Unwrap() error {
return e.Cause
}
func serverRegistrationErrorFromRPC(err error) ServerRegisterTunnelError {
if retryable, ok := err.(*tunnelpogs.RetryableError); ok {
return ServerRegisterTunnelError{
Cause: retryable.Unwrap(),
Permanent: false,
}
}
return ServerRegisterTunnelError{
Cause: err,
Permanent: true,
}
}
type ControlStreamError struct {
Cause error
}
var _ error = &ControlStreamError{}
func (e *ControlStreamError) Error() string {
return fmt.Sprintf("control stream error: %s", e.Cause)
}
func (e *ControlStreamError) Unwrap() error {
return e.Cause
}
type StreamListenerError struct {
Cause error
}
var _ error = &StreamListenerError{}
func (e *StreamListenerError) Error() string {
return fmt.Sprintf("accept stream listener error: %s", e.Cause)
}
func (e *StreamListenerError) Unwrap() error {
return e.Cause
}
type DatagramManagerError struct {
Cause error
}
var _ error = &DatagramManagerError{}
func (e *DatagramManagerError) Error() string {
return fmt.Sprintf("datagram manager error: %s", e.Cause)
}
func (e *DatagramManagerError) Unwrap() error {
return e.Cause
}