8174d88bac
For consistency and also because the SafeErrorWrapperBuilder seems to be the building pattern than the original code assumed. New code should not use it, but I'd rather keep legacy code consistent formally and with its own original assumptions. In particular, it matters that SafeErrorWrapperBuilder assigns the most relevant operation that failed. We were not doing that when we were manually creating a new ErrWrapper. Part of https://github.com/ooni/probe/issues/1591
99 lines
2.8 KiB
Go
99 lines
2.8 KiB
Go
package errorsx
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"net"
|
|
|
|
"github.com/lucas-clemente/quic-go"
|
|
"github.com/ooni/probe-cli/v3/internal/netxlite/errorsx"
|
|
"github.com/ooni/probe-cli/v3/internal/netxlite/quicx"
|
|
)
|
|
|
|
// QUICContextDialer is a dialer for QUIC using Context.
|
|
type QUICContextDialer interface {
|
|
// DialContext establishes a new QUIC session using the given
|
|
// network and address. The tlsConfig and the quicConfig arguments
|
|
// MUST NOT be nil. Returns either the session or an error.
|
|
DialContext(ctx context.Context, network, address string,
|
|
tlsConfig *tls.Config, quicConfig *quic.Config) (quic.EarlySession, error)
|
|
}
|
|
|
|
// QUICListener listens for QUIC connections.
|
|
type QUICListener interface {
|
|
// Listen creates a new listening UDPConn.
|
|
Listen(addr *net.UDPAddr) (quicx.UDPLikeConn, error)
|
|
}
|
|
|
|
// ErrorWrapperQUICListener is a QUICListener that wraps errors.
|
|
type ErrorWrapperQUICListener struct {
|
|
// QUICListener is the underlying listener.
|
|
QUICListener QUICListener
|
|
}
|
|
|
|
var _ QUICListener = &ErrorWrapperQUICListener{}
|
|
|
|
// Listen implements QUICListener.Listen.
|
|
func (qls *ErrorWrapperQUICListener) Listen(addr *net.UDPAddr) (quicx.UDPLikeConn, error) {
|
|
pconn, err := qls.QUICListener.Listen(addr)
|
|
if err != nil {
|
|
return nil, SafeErrWrapperBuilder{
|
|
Error: err,
|
|
Operation: errorsx.QUICListenOperation,
|
|
}.MaybeBuild()
|
|
}
|
|
return &errorWrapperUDPConn{pconn}, nil
|
|
}
|
|
|
|
// errorWrapperUDPConn is a quicx.UDPLikeConn that wraps errors.
|
|
type errorWrapperUDPConn struct {
|
|
// UDPLikeConn is the underlying conn.
|
|
quicx.UDPLikeConn
|
|
}
|
|
|
|
var _ quicx.UDPLikeConn = &errorWrapperUDPConn{}
|
|
|
|
// WriteTo implements quicx.UDPLikeConn.WriteTo.
|
|
func (c *errorWrapperUDPConn) WriteTo(p []byte, addr net.Addr) (int, error) {
|
|
count, err := c.UDPLikeConn.WriteTo(p, addr)
|
|
if err != nil {
|
|
return 0, SafeErrWrapperBuilder{
|
|
Error: err,
|
|
Operation: errorsx.WriteToOperation,
|
|
}.MaybeBuild()
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
// ReadFrom implements quicx.UDPLikeConn.ReadFrom.
|
|
func (c *errorWrapperUDPConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
|
n, addr, err := c.UDPLikeConn.ReadFrom(b)
|
|
if err != nil {
|
|
return 0, nil, SafeErrWrapperBuilder{
|
|
Error: err,
|
|
Operation: errorsx.ReadFromOperation,
|
|
}.MaybeBuild()
|
|
}
|
|
return n, addr, nil
|
|
}
|
|
|
|
// ErrorWrapperQUICDialer is a dialer that performs quic err wrapping
|
|
type ErrorWrapperQUICDialer struct {
|
|
Dialer QUICContextDialer
|
|
}
|
|
|
|
// DialContext implements ContextDialer.DialContext
|
|
func (d *ErrorWrapperQUICDialer) DialContext(
|
|
ctx context.Context, network string, host string,
|
|
tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlySession, error) {
|
|
sess, err := d.Dialer.DialContext(ctx, network, host, tlsCfg, cfg)
|
|
if err != nil {
|
|
return nil, SafeErrWrapperBuilder{
|
|
Classifier: errorsx.ClassifyQUICHandshakeError,
|
|
Error: err,
|
|
Operation: errorsx.QUICHandshakeOperation,
|
|
}.MaybeBuild()
|
|
}
|
|
return sess, nil
|
|
}
|