2019-05-22 21:23:23 +00:00
|
|
|
package netutil
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net"
|
2023-08-29 09:46:39 +00:00
|
|
|
"syscall"
|
2019-05-22 21:23:23 +00:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/VictoriaMetrics/metrics"
|
|
|
|
)
|
|
|
|
|
2023-08-29 10:45:57 +00:00
|
|
|
// A dialer is a means to establish a connection.
|
|
|
|
type dialer interface {
|
|
|
|
Dial(network, addr string) (c net.Conn, err error)
|
|
|
|
}
|
|
|
|
|
2019-05-22 21:23:23 +00:00
|
|
|
// NewTCPDialer returns new dialer for dialing the given addr.
|
|
|
|
//
|
|
|
|
// The name is used in metric tags for the returned dialer.
|
|
|
|
// The name must be unique among dialers.
|
2023-08-29 10:09:24 +00:00
|
|
|
func NewTCPDialer(ms *metrics.Set, name, addr string, dialTimeout, userTimeout time.Duration) *TCPDialer {
|
2023-08-29 10:45:57 +00:00
|
|
|
nd := &net.Dialer{
|
|
|
|
Timeout: dialTimeout,
|
2019-05-22 21:23:23 +00:00
|
|
|
|
2023-08-29 10:45:57 +00:00
|
|
|
// How frequently to send keep-alive packets over established TCP connections.
|
|
|
|
KeepAlive: time.Second,
|
|
|
|
}
|
|
|
|
d := &TCPDialer{
|
|
|
|
d: nd,
|
2019-05-22 21:23:23 +00:00
|
|
|
addr: addr,
|
|
|
|
|
2022-10-25 11:41:56 +00:00
|
|
|
dials: ms.NewCounter(fmt.Sprintf(`vm_tcpdialer_dials_total{name=%q, addr=%q}`, name, addr)),
|
|
|
|
dialErrors: ms.NewCounter(fmt.Sprintf(`vm_tcpdialer_errors_total{name=%q, addr=%q, type="dial"}`, name, addr)),
|
2019-05-22 21:23:23 +00:00
|
|
|
}
|
2022-10-25 11:41:56 +00:00
|
|
|
d.connMetrics.init(ms, "vm_tcpdialer", name, addr)
|
2023-08-29 09:46:39 +00:00
|
|
|
if userTimeout > 0 {
|
2023-08-29 10:45:57 +00:00
|
|
|
nd.Control = func(network, address string, c syscall.RawConn) error {
|
2023-08-29 10:09:24 +00:00
|
|
|
var err error
|
2023-08-29 09:46:39 +00:00
|
|
|
controlErr := c.Control(func(fd uintptr) {
|
|
|
|
err = setTCPUserTimeout(fd, userTimeout)
|
|
|
|
})
|
|
|
|
if controlErr != nil {
|
|
|
|
return controlErr
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2019-05-22 21:23:23 +00:00
|
|
|
return d
|
|
|
|
}
|
|
|
|
|
|
|
|
// TCPDialer is used for dialing the addr passed to NewTCPDialer.
|
|
|
|
//
|
|
|
|
// It also gathers various stats for dialed connections.
|
|
|
|
type TCPDialer struct {
|
2023-08-29 10:45:57 +00:00
|
|
|
d dialer
|
2019-05-22 21:23:23 +00:00
|
|
|
|
|
|
|
addr string
|
|
|
|
|
|
|
|
dials *metrics.Counter
|
|
|
|
dialErrors *metrics.Counter
|
|
|
|
|
|
|
|
connMetrics
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dial dials the addr passed to NewTCPDialer.
|
|
|
|
func (d *TCPDialer) Dial() (net.Conn, error) {
|
|
|
|
d.dials.Inc()
|
2021-03-16 22:16:06 +00:00
|
|
|
network := GetTCPNetwork()
|
2019-12-01 00:52:22 +00:00
|
|
|
c, err := d.d.Dial(network, d.addr)
|
2019-05-22 21:23:23 +00:00
|
|
|
if err != nil {
|
|
|
|
d.dialErrors.Inc()
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
d.conns.Inc()
|
|
|
|
sc := &statConn{
|
|
|
|
Conn: c,
|
|
|
|
cm: &d.connMetrics,
|
|
|
|
}
|
|
|
|
return sc, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Addr returns the address the dialer dials to.
|
|
|
|
func (d *TCPDialer) Addr() string {
|
|
|
|
return d.addr
|
|
|
|
}
|