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
|
|
|
|
|
2022-05-15 19:25:27 +02:00
|
|
|
//
|
|
|
|
// Code for dialing TCP or UDP net.Conn-like connections
|
|
|
|
//
|
|
|
|
|
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
|
|
|
import (
|
|
|
|
"context"
|
2021-09-06 14:12:30 +02:00
|
|
|
"errors"
|
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
|
|
|
"net"
|
2021-09-06 14:12:30 +02:00
|
|
|
"sync"
|
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
|
|
|
"time"
|
2021-09-05 19:55:28 +02:00
|
|
|
|
2022-01-03 13:53:23 +01:00
|
|
|
"github.com/ooni/probe-cli/v3/internal/model"
|
|
|
|
)
|
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
|
|
|
|
2022-06-05 18:44:17 +02:00
|
|
|
// NewDialerWithStdlibResolver is equivalent to creating a system resolver
|
2022-06-06 14:46:44 +02:00
|
|
|
// using NewStdlibResolver and then a dialer using NewDialerWithResolver where
|
2022-06-05 18:44:17 +02:00
|
|
|
// the resolver argument is the previously created resolver.
|
|
|
|
func NewDialerWithStdlibResolver(dl model.DebugLogger) model.Dialer {
|
2022-06-06 14:46:44 +02:00
|
|
|
reso := NewStdlibResolver(dl)
|
2022-06-05 18:44:17 +02:00
|
|
|
return NewDialerWithResolver(dl, reso)
|
|
|
|
}
|
|
|
|
|
2022-05-31 20:02:11 +02:00
|
|
|
// NewDialerWithResolver is equivalent to calling WrapDialer with
|
|
|
|
// the dialer argument being equal to &DialerSystem{}.
|
2022-06-01 08:31:20 +02:00
|
|
|
func NewDialerWithResolver(dl model.DebugLogger, r model.Resolver, w ...model.DialerWrapper) model.Dialer {
|
2022-05-31 20:02:11 +02:00
|
|
|
return WrapDialer(dl, r, &DialerSystem{}, w...)
|
2021-09-27 12:00:43 +02:00
|
|
|
}
|
|
|
|
|
2022-05-31 20:02:11 +02:00
|
|
|
// WrapDialer wraps an existing Dialer to add extra functionality
|
|
|
|
// such as separting DNS lookup and connecting, error wrapping, logging, etc.
|
|
|
|
//
|
|
|
|
// When possible use NewDialerWithResolver or NewDialerWithoutResolver
|
|
|
|
// instead of using this rather low-level function.
|
|
|
|
//
|
2022-10-12 17:38:33 +02:00
|
|
|
// # Arguments
|
2022-05-31 20:02:11 +02:00
|
|
|
//
|
|
|
|
// 1. logger is used to emit debug messages (MUST NOT be nil);
|
|
|
|
//
|
|
|
|
// 2. resolver is the resolver to use when dialing for endpoint
|
|
|
|
// addresses containing domain names (MUST NOT be nil);
|
|
|
|
//
|
|
|
|
// 3. baseDialer is the dialer to wrap (MUST NOT be nil);
|
|
|
|
//
|
|
|
|
// 4. wrappers is a list of zero or more functions allowing you to
|
2022-06-01 08:31:20 +02:00
|
|
|
// modify the behavior of the returned dialer (see below). Please note
|
|
|
|
// that this function will just ignore any nil wrapper.
|
2021-09-08 00:00:53 +02:00
|
|
|
//
|
2022-10-12 17:38:33 +02:00
|
|
|
// # Return value
|
2021-09-08 00:00:53 +02:00
|
|
|
//
|
2022-05-31 20:02:11 +02:00
|
|
|
// The returned dialer is an opaque type consisting of the composition of
|
|
|
|
// several simple dialers. The following pseudo code illustrates the general
|
|
|
|
// behavior of the returned composed dialer:
|
2021-09-08 00:00:53 +02:00
|
|
|
//
|
2022-10-12 17:38:33 +02:00
|
|
|
// addrs, err := dnslookup()
|
|
|
|
// if err != nil {
|
|
|
|
// return nil, err
|
|
|
|
// }
|
|
|
|
// errors := []error{}
|
|
|
|
// for _, a := range addrs {
|
|
|
|
// conn, err := tcpconnect(a)
|
|
|
|
// if err != nil {
|
|
|
|
// errors = append(errors, err)
|
|
|
|
// continue
|
|
|
|
// }
|
|
|
|
// return conn, nil
|
|
|
|
// }
|
|
|
|
// return nil, errors[0]
|
2021-09-08 21:19:51 +02:00
|
|
|
//
|
2022-05-31 20:02:11 +02:00
|
|
|
// The following table describes the structure of the returned dialer:
|
2021-09-08 21:19:51 +02:00
|
|
|
//
|
2022-10-12 17:38:33 +02:00
|
|
|
// +-------+-----------------+------------------------------------------+
|
|
|
|
// | Index | Name | Description |
|
|
|
|
// +-------+-----------------+------------------------------------------+
|
|
|
|
// | 0 | base | the baseDialer argument |
|
|
|
|
// +-------+-----------------+------------------------------------------+
|
|
|
|
// | 1 | errWrapper | wraps Go errors to be consistent with |
|
|
|
|
// | | | OONI df-007-errors spec |
|
|
|
|
// +-------+-----------------+------------------------------------------+
|
|
|
|
// | 2 | ??? | if there are wrappers, result of calling |
|
|
|
|
// | | | the first one on the errWrapper dialer |
|
|
|
|
// +-------+-----------------+------------------------------------------+
|
|
|
|
// | ... | ... | ... |
|
|
|
|
// +-------+-----------------+------------------------------------------+
|
|
|
|
// | N | ??? | if there are wrappers, result of calling |
|
|
|
|
// | | | the last one on the N-1 dialer |
|
|
|
|
// +-------+-----------------+------------------------------------------+
|
|
|
|
// | N+1 | logger (inner) | logs TCP connect operations |
|
|
|
|
// +-------+-----------------+------------------------------------------+
|
|
|
|
// | N+2 | resolver | DNS lookup and try connect each IP in |
|
|
|
|
// | | | sequence until one of them succeeds |
|
|
|
|
// +-------+-----------------+------------------------------------------+
|
|
|
|
// | N+3 | logger (outer) | logs the overall dial operation |
|
|
|
|
// +-------+-----------------+------------------------------------------+
|
2021-09-08 22:48:10 +02:00
|
|
|
//
|
2022-05-31 20:02:11 +02:00
|
|
|
// The list of wrappers allows to insert modified dialers in the correct
|
|
|
|
// place for observing and saving I/O events (connect, read, etc.).
|
2021-09-29 20:21:25 +02:00
|
|
|
//
|
2022-10-12 17:38:33 +02:00
|
|
|
// # Remarks
|
2022-05-31 20:02:11 +02:00
|
|
|
//
|
|
|
|
// When the resolver is &NullResolver{} any attempt to perform DNS resolutions
|
|
|
|
// in the dialer at index N+2 will fail with ErrNoResolver.
|
|
|
|
//
|
|
|
|
// Otherwise, the dialer at index N+2 will try each resolver IP address
|
|
|
|
// sequentially. In case of failure, such a resolver will return the first
|
|
|
|
// error that occurred. This implementation strategy is a QUIRK that is
|
|
|
|
// documented at TODO(https://github.com/ooni/probe/issues/1779).
|
|
|
|
//
|
|
|
|
// If the baseDialer is &DialerSystem{}, there will be a fixed TCP connect
|
|
|
|
// timeout for each connect operation. Because there may be multiple IP
|
|
|
|
// addresses per dial, the overall timeout would be a multiple of the timeout
|
|
|
|
// of a single connect operation. You may want to use the context to reduce
|
|
|
|
// the overall time spent trying all addresses and timing out.
|
|
|
|
func WrapDialer(logger model.DebugLogger, resolver model.Resolver,
|
2022-06-01 08:31:20 +02:00
|
|
|
baseDialer model.Dialer, wrappers ...model.DialerWrapper) (outDialer model.Dialer) {
|
2022-05-31 20:02:11 +02:00
|
|
|
outDialer = &dialerErrWrapper{
|
|
|
|
Dialer: baseDialer,
|
|
|
|
}
|
|
|
|
for _, wrapper := range wrappers {
|
2022-06-01 08:31:20 +02:00
|
|
|
if wrapper == nil {
|
|
|
|
continue // ignore as documented
|
|
|
|
}
|
|
|
|
outDialer = wrapper.WrapDialer(outDialer) // extend with user-supplied constructors
|
2022-05-31 20:02:11 +02:00
|
|
|
}
|
2021-09-05 20:41:46 +02:00
|
|
|
return &dialerLogger{
|
2022-07-01 12:22:22 +02:00
|
|
|
Dialer: &dialerResolverWithTracing{
|
2021-09-05 20:41:46 +02:00
|
|
|
Dialer: &dialerLogger{
|
2022-05-31 20:02:11 +02:00
|
|
|
Dialer: outDialer,
|
2022-01-03 13:53:23 +01:00
|
|
|
DebugLogger: logger,
|
2021-09-06 21:34:14 +02:00
|
|
|
operationSuffix: "_address",
|
2021-09-05 20:41:46 +02:00
|
|
|
},
|
|
|
|
Resolver: resolver,
|
|
|
|
},
|
2022-01-03 13:53:23 +01:00
|
|
|
DebugLogger: logger,
|
2021-09-05 20:41:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-31 20:02:11 +02:00
|
|
|
// NewDialerWithoutResolver is equivalent to calling NewDialerWithResolver
|
|
|
|
// with the resolver argument being &NullResolver{}.
|
2022-06-01 08:31:20 +02:00
|
|
|
func NewDialerWithoutResolver(dl model.DebugLogger, w ...model.DialerWrapper) model.Dialer {
|
2022-05-31 20:02:11 +02:00
|
|
|
return NewDialerWithResolver(dl, &NullResolver{}, w...)
|
2021-09-05 20:41:46 +02:00
|
|
|
}
|
|
|
|
|
2022-08-23 11:43:44 +02:00
|
|
|
// DialerSystem is a model.Dialer that uses the stdlib's net.Dialer
|
2022-05-31 20:02:11 +02:00
|
|
|
// to construct the new SimpleDialer used for dialing. This dialer has
|
|
|
|
// a fixed timeout for each connect operation equal to 15 seconds.
|
|
|
|
type DialerSystem struct {
|
|
|
|
// timeout is the OPTIONAL timeout (for testing).
|
2021-09-08 00:00:53 +02:00
|
|
|
timeout time.Duration
|
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
|
|
|
}
|
|
|
|
|
2022-05-31 20:02:11 +02:00
|
|
|
var _ model.Dialer = &DialerSystem{}
|
2021-09-08 21:19:51 +02:00
|
|
|
|
|
|
|
const dialerDefaultTimeout = 15 * time.Second
|
|
|
|
|
2022-10-12 17:38:33 +02:00
|
|
|
func (d *DialerSystem) configuredTimeout() time.Duration {
|
2021-09-08 00:00:53 +02:00
|
|
|
t := d.timeout
|
|
|
|
if t <= 0 {
|
2021-09-08 21:19:51 +02:00
|
|
|
t = dialerDefaultTimeout
|
2021-09-08 00:00:53 +02:00
|
|
|
}
|
2022-10-12 17:38:33 +02:00
|
|
|
return t
|
2021-09-08 00:00:53 +02:00
|
|
|
}
|
2021-09-05 19:55:28 +02:00
|
|
|
|
2022-05-31 20:02:11 +02:00
|
|
|
func (d *DialerSystem) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
|
2022-10-12 17:38:33 +02:00
|
|
|
return TProxy.DialContext(ctx, d.configuredTimeout(), network, address)
|
2021-09-05 19:55:28 +02:00
|
|
|
}
|
|
|
|
|
2022-05-31 20:02:11 +02:00
|
|
|
func (d *DialerSystem) CloseIdleConnections() {
|
2021-09-08 21:19:51 +02:00
|
|
|
// nothing to do here
|
2021-09-05 19:55:28 +02:00
|
|
|
}
|
|
|
|
|
2022-07-01 12:22:22 +02:00
|
|
|
// dialerResolverWithTracing combines dialing with domain name resolution and
|
|
|
|
// implements hooks to trace TCP (or UDP) connect operations.
|
|
|
|
type dialerResolverWithTracing struct {
|
2022-05-15 19:25:27 +02:00
|
|
|
Dialer model.Dialer
|
|
|
|
Resolver model.Resolver
|
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
|
|
|
}
|
|
|
|
|
2022-07-01 12:22:22 +02:00
|
|
|
var _ model.Dialer = &dialerResolverWithTracing{}
|
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
|
|
|
|
2022-07-01 12:22:22 +02:00
|
|
|
// DialContext implements model.Dialer.DialContext. Specifically this
|
|
|
|
// method performs the following operations:
|
|
|
|
//
|
|
|
|
// 1. resolve the domain inside the address using a resolver;
|
|
|
|
//
|
|
|
|
// 2. cycle through the available IP addresses and try to dial each of them;
|
|
|
|
//
|
|
|
|
// 3. trace the TCP (or UDP) connect and allow wrapping the returned conn.
|
|
|
|
func (d *dialerResolverWithTracing) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
|
2021-09-08 21:19:51 +02:00
|
|
|
// QUIRK: this routine and the related routines in quirks.go cannot
|
|
|
|
// be changed easily until we use events tracing to measure.
|
|
|
|
//
|
|
|
|
// Reference issue: TODO(https://github.com/ooni/probe/issues/1779).
|
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
|
|
|
onlyhost, onlyport, err := net.SplitHostPort(address)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-06-23 17:00:44 +02:00
|
|
|
addrs, err := d.lookupHost(ctx, onlyhost)
|
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 err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-09-06 20:17:45 +02:00
|
|
|
addrs = quirkSortIPAddrs(addrs)
|
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
|
|
|
var errorslist []error
|
2022-07-01 12:22:22 +02:00
|
|
|
trace := ContextTraceOrDefault(ctx)
|
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
|
|
|
for _, addr := range addrs {
|
|
|
|
target := net.JoinHostPort(addr, onlyport)
|
2022-07-01 12:22:22 +02:00
|
|
|
started := trace.TimeNow()
|
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
|
|
|
conn, err := d.Dialer.DialContext(ctx, network, target)
|
2022-07-01 12:22:22 +02:00
|
|
|
finished := trace.TimeNow()
|
|
|
|
// TODO(bassosimone): to make the code robust to future refactoring we have
|
|
|
|
// moved error wrapping inside this type. This change opens up the possibility
|
|
|
|
// of simplifying the dialing chain by removing dialerErrWrapper. We'll be
|
|
|
|
// able to implement this refactoring once netx is gone. We cannot complete
|
|
|
|
// this refactoring _before_ because WrapDialer inserts extra wrappers
|
|
|
|
// provided by netx in the dialers chain _before_ this dialer and the dialers
|
|
|
|
// that netx insert assume that they wrap a dialer with error wrapping.
|
|
|
|
//
|
|
|
|
// Because error wrapping should be idempotent, it should not be a problem
|
|
|
|
// to have two error wrapping dialers in the chain except that, of course, it
|
|
|
|
// would be less efficient than just having a single wrapper.
|
|
|
|
err = MaybeNewErrWrapper(ClassifyGenericError, ConnectOperation, err)
|
|
|
|
trace.OnConnectDone(started, network, onlyhost, target, err, finished)
|
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 err == nil {
|
2022-07-01 12:22:22 +02:00
|
|
|
conn = &dialerErrWrapperConn{conn}
|
2022-08-17 20:58:06 +02:00
|
|
|
return trace.MaybeWrapNetConn(conn), nil
|
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
|
|
|
}
|
|
|
|
errorslist = append(errorslist, err)
|
|
|
|
}
|
2021-09-06 20:17:45 +02:00
|
|
|
return nil, quirkReduceErrors(errorslist)
|
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-08 21:19:51 +02:00
|
|
|
// lookupHost ensures we correctly handle IP addresses.
|
2022-07-01 12:22:22 +02:00
|
|
|
func (d *dialerResolverWithTracing) lookupHost(ctx context.Context, hostname string) ([]string, 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 net.ParseIP(hostname) != nil {
|
|
|
|
return []string{hostname}, nil
|
|
|
|
}
|
|
|
|
return d.Resolver.LookupHost(ctx, hostname)
|
|
|
|
}
|
|
|
|
|
2022-07-01 12:22:22 +02:00
|
|
|
func (d *dialerResolverWithTracing) CloseIdleConnections() {
|
2021-09-05 19:55:28 +02:00
|
|
|
d.Dialer.CloseIdleConnections()
|
|
|
|
d.Resolver.CloseIdleConnections()
|
|
|
|
}
|
|
|
|
|
2021-09-05 14:49:38 +02:00
|
|
|
// dialerLogger is a Dialer with logging.
|
|
|
|
type dialerLogger struct {
|
2021-06-23 17:00:44 +02:00
|
|
|
// Dialer is the underlying dialer.
|
2022-05-15 19:25:27 +02:00
|
|
|
Dialer model.Dialer
|
2021-06-23 17:00:44 +02:00
|
|
|
|
2022-05-15 19:25:27 +02:00
|
|
|
// DebugLogger is the underlying logger.
|
|
|
|
DebugLogger model.DebugLogger
|
2021-09-06 21:34:14 +02:00
|
|
|
|
|
|
|
// 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
|
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
|
|
|
}
|
|
|
|
|
2022-01-03 13:53:23 +01:00
|
|
|
var _ model.Dialer = &dialerLogger{}
|
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
|
|
|
func (d *dialerLogger) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
|
2022-01-03 13:53:23 +01:00
|
|
|
d.DebugLogger.Debugf("dial%s %s/%s...", d.operationSuffix, address, network)
|
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
|
|
|
start := time.Now()
|
|
|
|
conn, err := d.Dialer.DialContext(ctx, network, address)
|
2021-06-23 17:00:44 +02:00
|
|
|
elapsed := time.Since(start)
|
|
|
|
if err != nil {
|
2022-01-03 13:53:23 +01:00
|
|
|
d.DebugLogger.Debugf("dial%s %s/%s... %s in %s", d.operationSuffix,
|
2021-09-06 21:34:14 +02:00
|
|
|
address, network, err, elapsed)
|
2021-06-23 17:00:44 +02:00
|
|
|
return nil, err
|
|
|
|
}
|
2022-01-03 13:53:23 +01:00
|
|
|
d.DebugLogger.Debugf("dial%s %s/%s... ok in %s", d.operationSuffix,
|
2021-09-06 21:34:14 +02:00
|
|
|
address, network, elapsed)
|
2021-06-23 17:00:44 +02:00
|
|
|
return conn, nil
|
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 19:55:28 +02:00
|
|
|
|
|
|
|
func (d *dialerLogger) CloseIdleConnections() {
|
|
|
|
d.Dialer.CloseIdleConnections()
|
|
|
|
}
|
2021-09-06 14:12:30 +02:00
|
|
|
|
2021-09-29 20:21:25 +02:00
|
|
|
// ErrNoConnReuse is the type of error returned when you create a
|
|
|
|
// "single use" dialer or a "single use" TLS dialer and you dial
|
|
|
|
// more than once, which is not supported by such a dialer.
|
2021-09-06 14:12:30 +02:00
|
|
|
var ErrNoConnReuse = errors.New("cannot reuse connection")
|
|
|
|
|
2021-09-29 20:21:25 +02:00
|
|
|
// NewSingleUseDialer returns a "single use" dialer. The first
|
|
|
|
// dial will succed and return conn regardless of the network
|
|
|
|
// and address arguments passed to DialContext. Any subsequent
|
|
|
|
// dial returns ErrNoConnReuse.
|
2022-01-03 13:53:23 +01:00
|
|
|
func NewSingleUseDialer(conn net.Conn) model.Dialer {
|
2021-09-06 14:12:30 +02:00
|
|
|
return &dialerSingleUse{conn: conn}
|
|
|
|
}
|
|
|
|
|
2021-09-06 22:14:49 +02:00
|
|
|
// dialerSingleUse is the Dialer returned by NewSingleDialer.
|
2021-09-06 14:12:30 +02:00
|
|
|
type dialerSingleUse struct {
|
2022-05-15 19:25:27 +02:00
|
|
|
mu sync.Mutex
|
2021-09-06 14:12:30 +02:00
|
|
|
conn net.Conn
|
|
|
|
}
|
|
|
|
|
2022-01-03 13:53:23 +01:00
|
|
|
var _ model.Dialer = &dialerSingleUse{}
|
2021-09-06 14:12:30 +02:00
|
|
|
|
|
|
|
func (s *dialerSingleUse) DialContext(ctx context.Context, network string, addr string) (net.Conn, error) {
|
2022-05-15 19:25:27 +02:00
|
|
|
defer s.mu.Unlock()
|
|
|
|
s.mu.Lock()
|
2021-09-06 14:12:30 +02:00
|
|
|
if s.conn == nil {
|
|
|
|
return nil, ErrNoConnReuse
|
|
|
|
}
|
|
|
|
var conn net.Conn
|
|
|
|
conn, s.conn = s.conn, nil
|
|
|
|
return conn, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *dialerSingleUse) CloseIdleConnections() {
|
2021-09-08 21:19:51 +02:00
|
|
|
// nothing to do
|
2021-09-06 14:12:30 +02:00
|
|
|
}
|
2021-09-07 19:56:42 +02:00
|
|
|
|
|
|
|
// dialerErrWrapper is a dialer that performs error wrapping. The connection
|
|
|
|
// returned by the DialContext function will also perform error wrapping.
|
|
|
|
type dialerErrWrapper struct {
|
2022-05-15 19:25:27 +02:00
|
|
|
Dialer model.Dialer
|
2021-09-07 19:56:42 +02:00
|
|
|
}
|
|
|
|
|
2022-01-03 13:53:23 +01:00
|
|
|
var _ model.Dialer = &dialerErrWrapper{}
|
2021-09-07 19:56:42 +02:00
|
|
|
|
|
|
|
func (d *dialerErrWrapper) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
|
|
|
|
conn, err := d.Dialer.DialContext(ctx, network, address)
|
|
|
|
if err != nil {
|
2022-07-01 12:22:22 +02:00
|
|
|
return nil, NewErrWrapper(ClassifyGenericError, ConnectOperation, err)
|
2021-09-07 19:56:42 +02:00
|
|
|
}
|
|
|
|
return &dialerErrWrapperConn{Conn: conn}, nil
|
|
|
|
}
|
|
|
|
|
2022-05-15 19:25:27 +02:00
|
|
|
func (d *dialerErrWrapper) CloseIdleConnections() {
|
|
|
|
d.Dialer.CloseIdleConnections()
|
|
|
|
}
|
|
|
|
|
2021-09-07 19:56:42 +02:00
|
|
|
// dialerErrWrapperConn is a net.Conn that performs error wrapping.
|
|
|
|
type dialerErrWrapperConn struct {
|
|
|
|
net.Conn
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ net.Conn = &dialerErrWrapperConn{}
|
|
|
|
|
|
|
|
func (c *dialerErrWrapperConn) Read(b []byte) (int, error) {
|
|
|
|
count, err := c.Conn.Read(b)
|
|
|
|
if err != nil {
|
2022-07-01 12:22:22 +02:00
|
|
|
return 0, NewErrWrapper(ClassifyGenericError, ReadOperation, err)
|
2021-09-07 19:56:42 +02:00
|
|
|
}
|
|
|
|
return count, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *dialerErrWrapperConn) Write(b []byte) (int, error) {
|
|
|
|
count, err := c.Conn.Write(b)
|
|
|
|
if err != nil {
|
2022-07-01 12:22:22 +02:00
|
|
|
return 0, NewErrWrapper(ClassifyGenericError, WriteOperation, err)
|
2021-09-07 19:56:42 +02:00
|
|
|
}
|
|
|
|
return count, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *dialerErrWrapperConn) Close() error {
|
|
|
|
err := c.Conn.Close()
|
|
|
|
if err != nil {
|
2022-07-01 12:22:22 +02:00
|
|
|
return NewErrWrapper(ClassifyGenericError, CloseOperation, err)
|
2021-09-07 19:56:42 +02:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2021-09-08 14:46:17 +02:00
|
|
|
|
2021-09-29 20:21:25 +02:00
|
|
|
// ErrNoDialer is the type of error returned by "null" dialers
|
|
|
|
// when you attempt to dial with them.
|
2021-09-08 14:46:17 +02:00
|
|
|
var ErrNoDialer = errors.New("no configured dialer")
|
|
|
|
|
2021-09-29 20:21:25 +02:00
|
|
|
// NewNullDialer returns a dialer that always fails with ErrNoDialer.
|
2022-01-03 13:53:23 +01:00
|
|
|
func NewNullDialer() model.Dialer {
|
2021-09-08 14:46:17 +02:00
|
|
|
return &nullDialer{}
|
|
|
|
}
|
|
|
|
|
|
|
|
type nullDialer struct{}
|
|
|
|
|
2022-01-03 13:53:23 +01:00
|
|
|
var _ model.Dialer = &nullDialer{}
|
2021-09-08 14:46:17 +02:00
|
|
|
|
|
|
|
func (*nullDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
|
|
|
|
return nil, ErrNoDialer
|
|
|
|
}
|
|
|
|
|
|
|
|
func (*nullDialer) CloseIdleConnections() {
|
|
|
|
// nothing to do
|
|
|
|
}
|