refactor: start pivoting netx (#396)
What do I mean by pivoting? Netx is currently organized by row:
```
| dialer | quicdialer | resolver | ...
saving | | | | ...
errorwrapping | | | | ...
logging | | | | ...
mocking/sys | | | | ...
```
Every row needs to implement saving, errorwrapping, logging, mocking (or
adapting to the system or to some underlying library).
This causes cross package dependencies and, in turn, complexity. For
example, we need the `trace` package for supporting saving.
And `dialer`, `quickdialer`, et al. need to depend on such a package.
The same goes for errorwrapping.
This arrangement further complicates testing. For example, I am
currently working on https://github.com/ooni/probe/issues/1505 and
I realize it need to repeat integration tests in multiple places.
Let's say instead we pivot the above matrix as follows:
```
| saving | errorwrapping | logging | ...
dialer | | | | ...
quicdialer | | | | ...
logging | | | | ...
mocking/sys | | | | ...
...
```
In this way, now every row contains everything related to a specific
action to perform. We can now share code without relying on extra
support packages. What's more, we can write tests and, judding from
the way in which things are made, it seems we only need integration
testing in `errorwrapping` because it's where data quality matters
whereas, in all other cases, unit testing is fine.
I am going, therefore, to proceed with these changes and "pivot"
`netx`. Hopefully, it won't be too painful.
2021-06-23 15:53:12 +02:00
|
|
|
package netxlite
|
|
|
|
|
|
|
|
import (
|
2021-09-05 18:03:50 +02:00
|
|
|
"context"
|
2021-09-06 20:56:14 +02:00
|
|
|
"crypto/tls"
|
2021-09-05 19:55:28 +02:00
|
|
|
"net"
|
2021-09-06 20:56:14 +02:00
|
|
|
|
|
|
|
"github.com/lucas-clemente/quic-go"
|
refactor: start pivoting netx (#396)
What do I mean by pivoting? Netx is currently organized by row:
```
| dialer | quicdialer | resolver | ...
saving | | | | ...
errorwrapping | | | | ...
logging | | | | ...
mocking/sys | | | | ...
```
Every row needs to implement saving, errorwrapping, logging, mocking (or
adapting to the system or to some underlying library).
This causes cross package dependencies and, in turn, complexity. For
example, we need the `trace` package for supporting saving.
And `dialer`, `quickdialer`, et al. need to depend on such a package.
The same goes for errorwrapping.
This arrangement further complicates testing. For example, I am
currently working on https://github.com/ooni/probe/issues/1505 and
I realize it need to repeat integration tests in multiple places.
Let's say instead we pivot the above matrix as follows:
```
| saving | errorwrapping | logging | ...
dialer | | | | ...
quicdialer | | | | ...
logging | | | | ...
mocking/sys | | | | ...
...
```
In this way, now every row contains everything related to a specific
action to perform. We can now share code without relying on extra
support packages. What's more, we can write tests and, judding from
the way in which things are made, it seems we only need integration
testing in `errorwrapping` because it's where data quality matters
whereas, in all other cases, unit testing is fine.
I am going, therefore, to proceed with these changes and "pivot"
`netx`. Hopefully, it won't be too painful.
2021-06-23 15:53:12 +02:00
|
|
|
)
|
|
|
|
|
2021-09-05 14:49:38 +02:00
|
|
|
// These vars export internal names to legacy ooni/probe-cli code.
|
2021-09-29 20:21:25 +02:00
|
|
|
//
|
|
|
|
// Deprecated: do not use these names in new code.
|
2021-09-05 14:49:38 +02:00
|
|
|
var (
|
2021-09-08 00:00:53 +02:00
|
|
|
DefaultDialer = &dialerSystem{}
|
2021-09-05 14:49:38 +02:00
|
|
|
DefaultTLSHandshaker = defaultTLSHandshaker
|
2021-09-05 20:59:42 +02:00
|
|
|
NewConnUTLS = newConnUTLS
|
2021-09-08 22:48:10 +02:00
|
|
|
DefaultResolver = &resolverSystem{}
|
2021-09-05 14:49:38 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// These types export internal names to legacy ooni/probe-cli code.
|
2021-09-29 20:21:25 +02:00
|
|
|
//
|
|
|
|
// Deprecated: do not use these names in new code.
|
2021-09-05 14:49:38 +02:00
|
|
|
type (
|
|
|
|
DialerResolver = dialerResolver
|
|
|
|
DialerLogger = dialerLogger
|
|
|
|
HTTPTransportLogger = httpTransportLogger
|
|
|
|
QUICListenerStdlib = quicListenerStdlib
|
|
|
|
QUICDialerQUICGo = quicDialerQUICGo
|
|
|
|
QUICDialerResolver = quicDialerResolver
|
|
|
|
QUICDialerLogger = quicDialerLogger
|
|
|
|
ResolverSystem = resolverSystem
|
|
|
|
ResolverLogger = resolverLogger
|
|
|
|
ResolverIDNA = resolverIDNA
|
|
|
|
TLSHandshakerConfigurable = tlsHandshakerConfigurable
|
|
|
|
TLSHandshakerLogger = tlsHandshakerLogger
|
2021-09-05 19:55:28 +02:00
|
|
|
DialerSystem = dialerSystem
|
2021-09-06 14:12:30 +02:00
|
|
|
TLSDialerLegacy = tlsDialer
|
2021-09-09 20:21:43 +02:00
|
|
|
AddressResolver = resolverShortCircuitIPAddr
|
2021-09-05 14:49:38 +02:00
|
|
|
)
|
2021-09-05 18:03:50 +02:00
|
|
|
|
|
|
|
// ResolverLegacy performs domain name resolutions.
|
|
|
|
//
|
2021-09-29 20:21:25 +02:00
|
|
|
// Deprecated: new code should use Resolver.
|
2021-09-05 18:03:50 +02:00
|
|
|
//
|
|
|
|
// Existing code in ooni/probe-cli is still using this definition.
|
|
|
|
type ResolverLegacy interface {
|
|
|
|
// LookupHost behaves like net.Resolver.LookupHost.
|
|
|
|
LookupHost(ctx context.Context, hostname string) (addrs []string, err error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewResolverLegacyAdapter adapts a ResolverLegacy to
|
|
|
|
// become compatible with the Resolver definition.
|
|
|
|
func NewResolverLegacyAdapter(reso ResolverLegacy) Resolver {
|
|
|
|
return &ResolverLegacyAdapter{reso}
|
|
|
|
}
|
|
|
|
|
2021-09-29 20:21:25 +02:00
|
|
|
// ResolverLegacyAdapter makes a ResolverLegacy behave like a Resolver.
|
2021-09-05 18:03:50 +02:00
|
|
|
type ResolverLegacyAdapter struct {
|
|
|
|
ResolverLegacy
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Resolver = &ResolverLegacyAdapter{}
|
|
|
|
|
|
|
|
type resolverLegacyNetworker interface {
|
|
|
|
Network() string
|
|
|
|
}
|
|
|
|
|
|
|
|
// Network implements Resolver.Network.
|
|
|
|
func (r *ResolverLegacyAdapter) Network() string {
|
|
|
|
if rn, ok := r.ResolverLegacy.(resolverLegacyNetworker); ok {
|
|
|
|
return rn.Network()
|
|
|
|
}
|
|
|
|
return "adapter"
|
|
|
|
}
|
|
|
|
|
|
|
|
type resolverLegacyAddresser interface {
|
|
|
|
Address() string
|
|
|
|
}
|
|
|
|
|
|
|
|
// Address implements Resolver.Address.
|
|
|
|
func (r *ResolverLegacyAdapter) Address() string {
|
|
|
|
if ra, ok := r.ResolverLegacy.(resolverLegacyAddresser); ok {
|
|
|
|
return ra.Address()
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
type resolverLegacyIdleConnectionsCloser interface {
|
|
|
|
CloseIdleConnections()
|
|
|
|
}
|
|
|
|
|
|
|
|
// CloseIdleConnections implements Resolver.CloseIdleConnections.
|
|
|
|
func (r *ResolverLegacyAdapter) CloseIdleConnections() {
|
|
|
|
if ra, ok := r.ResolverLegacy.(resolverLegacyIdleConnectionsCloser); ok {
|
|
|
|
ra.CloseIdleConnections()
|
|
|
|
}
|
|
|
|
}
|
2021-09-05 19:55:28 +02:00
|
|
|
|
2021-09-29 20:21:25 +02:00
|
|
|
// LookupHTTPS always returns ErrDNSNoTransport.
|
2021-09-27 23:09:41 +02:00
|
|
|
func (r *ResolverLegacyAdapter) LookupHTTPS(
|
|
|
|
ctx context.Context, domain string) (*HTTPSSvc, error) {
|
|
|
|
return nil, ErrNoDNSTransport
|
|
|
|
}
|
|
|
|
|
2021-09-05 19:55:28 +02:00
|
|
|
// DialerLegacy establishes network connections.
|
|
|
|
//
|
2021-09-29 20:21:25 +02:00
|
|
|
// Deprecated: please use Dialer instead.
|
2021-09-05 19:55:28 +02:00
|
|
|
//
|
|
|
|
// Existing code in probe-cli can use it until we
|
|
|
|
// have finished refactoring it.
|
|
|
|
type DialerLegacy interface {
|
|
|
|
// DialContext behaves like net.Dialer.DialContext.
|
|
|
|
DialContext(ctx context.Context, network, address string) (net.Conn, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewDialerLegacyAdapter adapts a DialerrLegacy to
|
|
|
|
// become compatible with the Dialer definition.
|
2021-09-29 20:21:25 +02:00
|
|
|
//
|
|
|
|
// Deprecated: do not use this function in new code.
|
2021-09-05 19:55:28 +02:00
|
|
|
func NewDialerLegacyAdapter(d DialerLegacy) Dialer {
|
|
|
|
return &DialerLegacyAdapter{d}
|
|
|
|
}
|
|
|
|
|
|
|
|
// DialerLegacyAdapter makes a DialerLegacy behave like
|
|
|
|
// it was a Dialer type. If DialerLegacy is actually also
|
|
|
|
// a Dialer, this adapter will just forward missing calls,
|
|
|
|
// otherwise it will implement a sensible default action.
|
|
|
|
type DialerLegacyAdapter struct {
|
|
|
|
DialerLegacy
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Dialer = &DialerLegacyAdapter{}
|
|
|
|
|
|
|
|
type dialerLegacyIdleConnectionsCloser interface {
|
|
|
|
CloseIdleConnections()
|
|
|
|
}
|
|
|
|
|
2021-09-29 20:21:25 +02:00
|
|
|
// CloseIdleConnections implements Dialer.CloseIdleConnections.
|
2021-09-05 19:55:28 +02:00
|
|
|
func (d *DialerLegacyAdapter) CloseIdleConnections() {
|
|
|
|
if ra, ok := d.DialerLegacy.(dialerLegacyIdleConnectionsCloser); ok {
|
|
|
|
ra.CloseIdleConnections()
|
|
|
|
}
|
|
|
|
}
|
2021-09-06 20:56:14 +02:00
|
|
|
|
|
|
|
// QUICContextDialer is a dialer for QUIC using Context.
|
|
|
|
//
|
2021-09-29 20:21:25 +02:00
|
|
|
// Deprecated: new code should use QUICDialer.
|
2021-09-06 20:56:14 +02:00
|
|
|
//
|
|
|
|
// Use NewQUICDialerFromContextDialerAdapter if you need to
|
2021-09-29 20:21:25 +02:00
|
|
|
// adapt to QUICDialer.
|
2021-09-06 20:56:14 +02:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewQUICDialerFromContextDialerAdapter creates a new
|
|
|
|
// QUICDialer from a QUICContextDialer.
|
|
|
|
func NewQUICDialerFromContextDialerAdapter(d QUICContextDialer) QUICDialer {
|
|
|
|
return &QUICContextDialerAdapter{d}
|
|
|
|
}
|
|
|
|
|
2021-09-29 20:21:25 +02:00
|
|
|
// QUICContextDialerAdapter adapts a QUICContextDialer to be a QUICDialer.
|
2021-09-06 20:56:14 +02:00
|
|
|
type QUICContextDialerAdapter struct {
|
|
|
|
QUICContextDialer
|
|
|
|
}
|
|
|
|
|
|
|
|
type quicContextDialerConnectionsCloser interface {
|
|
|
|
CloseIdleConnections()
|
|
|
|
}
|
|
|
|
|
|
|
|
// CloseIdleConnections implements QUICDialer.CloseIdleConnections.
|
|
|
|
func (d *QUICContextDialerAdapter) CloseIdleConnections() {
|
|
|
|
if o, ok := d.QUICContextDialer.(quicContextDialerConnectionsCloser); ok {
|
|
|
|
o.CloseIdleConnections()
|
|
|
|
}
|
|
|
|
}
|