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"
|
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
|
|
|
"errors"
|
2021-09-05 19:55:28 +02:00
|
|
|
"net"
|
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
|
|
|
"strings"
|
|
|
|
|
2021-07-01 16:34:36 +02:00
|
|
|
"github.com/ooni/probe-cli/v3/internal/errorsx"
|
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-06-25 18:38:13 +02:00
|
|
|
// reduceErrors finds a known error in a list of errors since
|
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
|
|
|
// it's probably most relevant.
|
|
|
|
//
|
|
|
|
// Deprecation warning
|
|
|
|
//
|
|
|
|
// Albeit still used, this function is now DEPRECATED.
|
|
|
|
//
|
|
|
|
// In perspective, we would like to transition to a scenario where
|
|
|
|
// full dialing is NOT used for measurements and we return a multierror here.
|
2021-06-25 18:38:13 +02:00
|
|
|
func reduceErrors(errorslist []error) error {
|
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
|
|
|
if len(errorslist) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
// If we have a known error, let's consider this the real error
|
|
|
|
// since it's probably most relevant. Otherwise let's return the
|
|
|
|
// first considering that (1) local resolvers likely will give
|
|
|
|
// us IPv4 first and (2) also our resolver does that. So, in case
|
|
|
|
// the user has no IPv6 connectivity, an IPv6 error is going to
|
|
|
|
// appear later in the list of errors.
|
|
|
|
for _, err := range errorslist {
|
2021-07-01 16:34:36 +02:00
|
|
|
var wrapper *errorsx.ErrWrapper
|
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
|
|
|
if errors.As(err, &wrapper) && !strings.HasPrefix(
|
|
|
|
err.Error(), "unknown_failure",
|
|
|
|
) {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// TODO(bassosimone): handle this case in a better way
|
|
|
|
return errorslist[0]
|
|
|
|
}
|
2021-09-05 14:49:38 +02:00
|
|
|
|
|
|
|
// These vars export internal names to legacy ooni/probe-cli code.
|
|
|
|
var (
|
|
|
|
DefaultDialer = defaultDialer
|
|
|
|
DefaultTLSHandshaker = defaultTLSHandshaker
|
2021-09-05 20:59:42 +02:00
|
|
|
NewConnUTLS = newConnUTLS
|
2021-09-05 14:49:38 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// These types export internal names to legacy ooni/probe-cli code.
|
|
|
|
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-05 14:49:38 +02:00
|
|
|
)
|
2021-09-05 18:03:50 +02:00
|
|
|
|
|
|
|
// ResolverLegacy performs domain name resolutions.
|
|
|
|
//
|
|
|
|
// This definition of Resolver is DEPRECATED. New code should use
|
|
|
|
// the more complete definition in the new Resolver interface.
|
|
|
|
//
|
|
|
|
// 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}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ResolverLegacyAdapter makes a ResolverLegacy behave like
|
|
|
|
// it was a Resolver type. If ResolverLegacy is actually also
|
|
|
|
// a Resolver, this adapter will just forward missing calls,
|
|
|
|
// otherwise it will implement a sensible default action.
|
|
|
|
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
|
|
|
|
|
|
|
// DialerLegacy establishes network connections.
|
|
|
|
//
|
|
|
|
// This definition is DEPRECATED. Please, use Dialer.
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
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()
|
|
|
|
}
|
|
|
|
|
|
|
|
// CloseIdleConnections implements Resolver.CloseIdleConnections.
|
|
|
|
func (d *DialerLegacyAdapter) CloseIdleConnections() {
|
|
|
|
if ra, ok := d.DialerLegacy.(dialerLegacyIdleConnectionsCloser); ok {
|
|
|
|
ra.CloseIdleConnections()
|
|
|
|
}
|
|
|
|
}
|