dialWithDNSCache resolves host:port through the cache, then dials the underlying TCP connection via baseDial. Falls through to baseDial directly when the address is already a literal IP or unparseable.
( cache *dnsCache, baseDial func(network, address string, timeout time.Duration) (net.Conn, error), network, address string, timeout time.Duration, )
| 70 | // underlying TCP connection via baseDial. Falls through to baseDial directly |
| 71 | // when the address is already a literal IP or unparseable. |
| 72 | func dialWithDNSCache( |
| 73 | cache *dnsCache, |
| 74 | baseDial func(network, address string, timeout time.Duration) (net.Conn, error), |
| 75 | network, address string, |
| 76 | timeout time.Duration, |
| 77 | ) (*dialResult, error) { |
| 78 | host, port, err := net.SplitHostPort(address) |
| 79 | if err != nil || net.ParseIP(host) != nil { |
| 80 | // Literal IP or malformed — let baseDial handle it. |
| 81 | tcpStart := time.Now() |
| 82 | conn, derr := baseDial(network, address, timeout) |
| 83 | if derr != nil { |
| 84 | return nil, derr |
| 85 | } |
| 86 | return &dialResult{Conn: conn, TCP: time.Since(tcpStart)}, nil |
| 87 | } |
| 88 | if ip := cache.get(host); ip != "" { |
| 89 | tcpStart := time.Now() |
| 90 | conn, derr := baseDial(network, net.JoinHostPort(ip, port), timeout) |
| 91 | tcpElapsed := time.Since(tcpStart) |
| 92 | if derr != nil { |
| 93 | // Cached IP failed; evict so the next call re-resolves. |
| 94 | cache.forget(host) |
| 95 | return nil, derr |
| 96 | } |
| 97 | return &dialResult{Conn: conn, DNSCached: true, TCP: tcpElapsed}, nil |
| 98 | } |
| 99 | // Cache miss: resolve, then dial. Use a context bounded by `timeout` |
| 100 | // so a slow resolver cannot eat the entire dial budget. |
| 101 | ctx, cancel := context.WithTimeout(context.Background(), timeout) |
| 102 | defer cancel() |
| 103 | dnsStart := time.Now() |
| 104 | addrs, lerr := net.DefaultResolver.LookupIPAddr(ctx, host) |
| 105 | dnsElapsed := time.Since(dnsStart) |
| 106 | if lerr != nil || len(addrs) == 0 { |
| 107 | // Fall through to baseDial which will surface the same/similar error. |
| 108 | tcpStart := time.Now() |
| 109 | conn, derr := baseDial(network, address, timeout) |
| 110 | if derr != nil { |
| 111 | return nil, derr |
| 112 | } |
| 113 | return &dialResult{Conn: conn, DNS: dnsElapsed, TCP: time.Since(tcpStart)}, nil |
| 114 | } |
| 115 | ip := addrs[0].IP.String() |
| 116 | cache.set(host, ip) |
| 117 | tcpStart := time.Now() |
| 118 | conn, derr := baseDial(network, net.JoinHostPort(ip, port), timeout) |
| 119 | tcpElapsed := time.Since(tcpStart) |
| 120 | if derr != nil { |
| 121 | return nil, derr |
| 122 | } |
| 123 | return &dialResult{Conn: conn, DNS: dnsElapsed, TCP: tcpElapsed}, nil |
| 124 | } |
no test coverage detected