feat(netxlite): write factories for quic code (#470)
Part of https://github.com/ooni/probe/issues/1591
This commit is contained in:
parent
3ba5626b95
commit
bdad392b61
|
@ -22,8 +22,9 @@ func NewDialerWithResolver(logger Logger, resolver Resolver) Dialer {
|
|||
return &dialerLogger{
|
||||
Dialer: &dialerResolver{
|
||||
Dialer: &dialerLogger{
|
||||
Dialer: &dialerSystem{},
|
||||
Logger: logger,
|
||||
Dialer: &dialerSystem{},
|
||||
Logger: logger,
|
||||
operationSuffix: "_address",
|
||||
},
|
||||
Resolver: resolver,
|
||||
},
|
||||
|
@ -120,21 +121,31 @@ type dialerLogger struct {
|
|||
|
||||
// Logger is the underlying logger.
|
||||
Logger Logger
|
||||
|
||||
// operationSuffix is appended to the operation name.
|
||||
//
|
||||
// We use this suffix to distinguish the output from dialing
|
||||
// with the output from dialing an IP address when we are
|
||||
// using a dialer without resolver, where otherwise both lines
|
||||
// would read something like `dial 8.8.8.8:443...`
|
||||
operationSuffix string
|
||||
}
|
||||
|
||||
var _ Dialer = &dialerLogger{}
|
||||
|
||||
// DialContext implements Dialer.DialContext
|
||||
func (d *dialerLogger) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
d.Logger.Debugf("dial %s/%s...", address, network)
|
||||
d.Logger.Debugf("dial%s %s/%s...", d.operationSuffix, address, network)
|
||||
start := time.Now()
|
||||
conn, err := d.Dialer.DialContext(ctx, network, address)
|
||||
elapsed := time.Since(start)
|
||||
if err != nil {
|
||||
d.Logger.Debugf("dial %s/%s... %s in %s", address, network, err, elapsed)
|
||||
d.Logger.Debugf("dial%s %s/%s... %s in %s", d.operationSuffix,
|
||||
address, network, err, elapsed)
|
||||
return nil, err
|
||||
}
|
||||
d.Logger.Debugf("dial %s/%s... ok in %s", address, network, elapsed)
|
||||
d.Logger.Debugf("dial%s %s/%s... ok in %s", d.operationSuffix,
|
||||
address, network, elapsed)
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,28 @@ import (
|
|||
"github.com/ooni/probe-cli/v3/internal/netxlite/quicx"
|
||||
)
|
||||
|
||||
// QUICListener listens for QUIC connections.
|
||||
type QUICListener interface {
|
||||
// Listen creates a new listening UDPConn.
|
||||
Listen(addr *net.UDPAddr) (quicx.UDPLikeConn, error)
|
||||
}
|
||||
|
||||
// NewQUICListener creates a new QUICListener using the standard
|
||||
// library to create listening UDP sockets.
|
||||
func NewQUICListener() QUICListener {
|
||||
return &quicListenerStdlib{}
|
||||
}
|
||||
|
||||
// quicListenerStdlib is a QUICListener using the standard library.
|
||||
type quicListenerStdlib struct{}
|
||||
|
||||
var _ QUICListener = &quicListenerStdlib{}
|
||||
|
||||
// Listen implements QUICListener.Listen.
|
||||
func (qls *quicListenerStdlib) Listen(addr *net.UDPAddr) (quicx.UDPLikeConn, error) {
|
||||
return net.ListenUDP("udp", addr)
|
||||
}
|
||||
|
||||
// QUICDialer dials QUIC sessions.
|
||||
type QUICDialer interface {
|
||||
// DialContext establishes a new QUIC session using the given
|
||||
|
@ -23,20 +45,32 @@ type QUICDialer interface {
|
|||
CloseIdleConnections()
|
||||
}
|
||||
|
||||
// QUICListener listens for QUIC connections.
|
||||
type QUICListener interface {
|
||||
// Listen creates a new listening UDPConn.
|
||||
Listen(addr *net.UDPAddr) (quicx.UDPLikeConn, error)
|
||||
// NewQUICDialerWithResolver returns a QUICDialer using the given
|
||||
// QUICListener to create listening connections and the given Resolver
|
||||
// to resolve domain names (if needed).
|
||||
func NewQUICDialerWithResolver(listener QUICListener,
|
||||
logger Logger, resolver Resolver) QUICDialer {
|
||||
return &quicDialerLogger{
|
||||
Dialer: &quicDialerResolver{
|
||||
Dialer: &quicDialerLogger{
|
||||
Dialer: &quicDialerQUICGo{
|
||||
QUICListener: listener,
|
||||
},
|
||||
Logger: logger,
|
||||
operationSuffix: "_address",
|
||||
},
|
||||
Resolver: resolver,
|
||||
},
|
||||
Logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// quicListenerStdlib is a QUICListener using the standard library.
|
||||
type quicListenerStdlib struct{}
|
||||
|
||||
var _ QUICListener = &quicListenerStdlib{}
|
||||
|
||||
// Listen implements QUICListener.Listen.
|
||||
func (qls *quicListenerStdlib) Listen(addr *net.UDPAddr) (quicx.UDPLikeConn, error) {
|
||||
return net.ListenUDP("udp", addr)
|
||||
// NewQUICDialerWithoutResolver is like NewQUICDialerWithResolver
|
||||
// except that there is no configured resolver. So, if you pass in
|
||||
// an address containing a domain name, the dial will fail with
|
||||
// the ErrNoResolver failure.
|
||||
func NewQUICDialerWithoutResolver(listener QUICListener, logger Logger) QUICDialer {
|
||||
return NewQUICDialerWithResolver(listener, logger, &nullResolver{})
|
||||
}
|
||||
|
||||
// quicDialerQUICGo dials using the lucas-clemente/quic-go library.
|
||||
|
@ -223,6 +257,14 @@ type quicDialerLogger struct {
|
|||
|
||||
// Logger is the underlying logger.
|
||||
Logger Logger
|
||||
|
||||
// operationSuffix is appended to the operation name.
|
||||
//
|
||||
// We use this suffix to distinguish the output from dialing
|
||||
// with the output from dialing an IP address when we are
|
||||
// using a dialer without resolver, where otherwise both lines
|
||||
// would read something like `dial 8.8.8.8:443...`
|
||||
operationSuffix string
|
||||
}
|
||||
|
||||
var _ QUICDialer = &quicDialerLogger{}
|
||||
|
@ -231,13 +273,14 @@ var _ QUICDialer = &quicDialerLogger{}
|
|||
func (d *quicDialerLogger) DialContext(
|
||||
ctx context.Context, network, address string,
|
||||
tlsConfig *tls.Config, quicConfig *quic.Config) (quic.EarlySession, error) {
|
||||
d.Logger.Debugf("quic %s/%s...", address, network)
|
||||
d.Logger.Debugf("quic_dial%s %s/%s...", d.operationSuffix, address, network)
|
||||
sess, err := d.Dialer.DialContext(ctx, network, address, tlsConfig, quicConfig)
|
||||
if err != nil {
|
||||
d.Logger.Debugf("quic %s/%s... %s", address, network, err)
|
||||
d.Logger.Debugf("quic_dial%s %s/%s... %s", d.operationSuffix,
|
||||
address, network, err)
|
||||
return nil, err
|
||||
}
|
||||
d.Logger.Debugf("quic %s/%s... ok", address, network)
|
||||
d.Logger.Debugf("quic_dial%s %s/%s... ok", d.operationSuffix, address, network)
|
||||
return sess, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -427,3 +427,36 @@ func TestQUICDialerLoggerFailure(t *testing.T) {
|
|||
t.Fatal("expected nil session")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewQUICDialerWithoutResolverChain(t *testing.T) {
|
||||
ql := NewQUICListener()
|
||||
dlr := NewQUICDialerWithoutResolver(ql, log.Log)
|
||||
dlog, okay := dlr.(*quicDialerLogger)
|
||||
if !okay {
|
||||
t.Fatal("invalid type")
|
||||
}
|
||||
if dlog.Logger != log.Log {
|
||||
t.Fatal("invalid logger")
|
||||
}
|
||||
dr, okay := dlog.Dialer.(*quicDialerResolver)
|
||||
if !okay {
|
||||
t.Fatal("invalid type")
|
||||
}
|
||||
if _, okay := dr.Resolver.(*nullResolver); !okay {
|
||||
t.Fatal("invalid resolver type")
|
||||
}
|
||||
dlog, okay = dr.Dialer.(*quicDialerLogger)
|
||||
if !okay {
|
||||
t.Fatal("invalid type")
|
||||
}
|
||||
if dlog.Logger != log.Log {
|
||||
t.Fatal("invalid logger")
|
||||
}
|
||||
dgo, okay := dlog.Dialer.(*quicDialerQUICGo)
|
||||
if !okay {
|
||||
t.Fatal("invalid type")
|
||||
}
|
||||
if dgo.QUICListener != ql {
|
||||
t.Fatal("invalid quic listener")
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user