87 lines
2.4 KiB
Go
87 lines
2.4 KiB
Go
|
package netxlite
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"net"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
// Dialer establishes network connections.
|
||
|
type Dialer interface {
|
||
|
// DialContext behaves like net.Dialer.DialContext.
|
||
|
DialContext(ctx context.Context, network, address string) (net.Conn, error)
|
||
|
}
|
||
|
|
||
|
// DefaultDialer is the Dialer we use by default.
|
||
|
var DefaultDialer = &net.Dialer{
|
||
|
Timeout: 15 * time.Second,
|
||
|
KeepAlive: 15 * time.Second,
|
||
|
}
|
||
|
|
||
|
var _ Dialer = DefaultDialer
|
||
|
|
||
|
// DialerResolver is a dialer that uses the configured Resolver to resolver a
|
||
|
// domain name to IP addresses, and the configured Dialer to connect.
|
||
|
type DialerResolver struct {
|
||
|
// Dialer is the underlying Dialer.
|
||
|
Dialer Dialer
|
||
|
|
||
|
// Resolver is the underlying Resolver.
|
||
|
Resolver Resolver
|
||
|
}
|
||
|
|
||
|
var _ Dialer = &DialerResolver{}
|
||
|
|
||
|
// DialContext implements Dialer.DialContext.
|
||
|
func (d *DialerResolver) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
|
||
|
onlyhost, onlyport, err := net.SplitHostPort(address)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
var addrs []string
|
||
|
addrs, err = d.lookupHost(ctx, onlyhost)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
// TODO(bassosimone): here we should be using multierror rather
|
||
|
// than just calling ReduceErrors. We are not ready to do that
|
||
|
// yet, though. To do that, we need first to modify nettests so
|
||
|
// that we actually avoid dialing when measuring.
|
||
|
var errorslist []error
|
||
|
for _, addr := range addrs {
|
||
|
target := net.JoinHostPort(addr, onlyport)
|
||
|
conn, err := d.Dialer.DialContext(ctx, network, target)
|
||
|
if err == nil {
|
||
|
return conn, nil
|
||
|
}
|
||
|
errorslist = append(errorslist, err)
|
||
|
}
|
||
|
return nil, ReduceErrors(errorslist)
|
||
|
}
|
||
|
|
||
|
// lookupHost performs a domain name resolution.
|
||
|
func (d *DialerResolver) lookupHost(ctx context.Context, hostname string) ([]string, error) {
|
||
|
if net.ParseIP(hostname) != nil {
|
||
|
return []string{hostname}, nil
|
||
|
}
|
||
|
return d.Resolver.LookupHost(ctx, hostname)
|
||
|
}
|
||
|
|
||
|
// DialerLogger is a Dialer with logging
|
||
|
type DialerLogger struct {
|
||
|
Dialer
|
||
|
Logger Logger
|
||
|
}
|
||
|
|
||
|
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)
|
||
|
start := time.Now()
|
||
|
conn, err := d.Dialer.DialContext(ctx, network, address)
|
||
|
stop := time.Now()
|
||
|
d.Logger.Debugf("dial %s/%s... %+v in %s", address, network, err, stop.Sub(start))
|
||
|
return conn, err
|
||
|
}
|