LEFT | RIGHT |
(no file at all) | |
1 // Copyright 2012 The Go Authors. All rights reserved. | 1 // Copyright 2012 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package net | 5 package net |
6 | 6 |
7 import "time" | 7 import "time" |
8 | 8 |
9 // protocols contains minimal mappings between internet protocol | 9 // protocols contains minimal mappings between internet protocol |
10 // names and numbers for platforms that don't have a complete list of | 10 // names and numbers for platforms that don't have a complete list of |
(...skipping 22 matching lines...) Expand all Loading... |
33 | 33 |
34 var lookupGroup singleflight | 34 var lookupGroup singleflight |
35 | 35 |
36 // lookupIPMerge wraps lookupIP, but makes sure that for any given | 36 // lookupIPMerge wraps lookupIP, but makes sure that for any given |
37 // host, only one lookup is in-flight at a time. The returned memory | 37 // host, only one lookup is in-flight at a time. The returned memory |
38 // is always owned by the caller. | 38 // is always owned by the caller. |
39 func lookupIPMerge(host string) (addrs []IP, err error) { | 39 func lookupIPMerge(host string) (addrs []IP, err error) { |
40 addrsi, err, shared := lookupGroup.Do(host, func() (interface{}, error)
{ | 40 addrsi, err, shared := lookupGroup.Do(host, func() (interface{}, error)
{ |
41 return lookupIP(host) | 41 return lookupIP(host) |
42 }) | 42 }) |
| 43 return lookupIPReturn(addrsi, err, shared) |
| 44 } |
| 45 |
| 46 // lookupIPReturn turns the return values from singleflight.Do into |
| 47 // the return values from LookupIP. |
| 48 func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IP, error) { |
43 if err != nil { | 49 if err != nil { |
44 return nil, err | 50 return nil, err |
45 } | 51 } |
46 » addrs = addrsi.([]IP) | 52 » addrs := addrsi.([]IP) |
47 if shared { | 53 if shared { |
48 clone := make([]IP, len(addrs)) | 54 clone := make([]IP, len(addrs)) |
49 copy(clone, addrs) | 55 copy(clone, addrs) |
50 addrs = clone | 56 addrs = clone |
51 } | 57 } |
52 return addrs, nil | 58 return addrs, nil |
53 } | 59 } |
54 | 60 |
| 61 // lookupIPDeadline looks up a hostname with a deadline. |
55 func lookupIPDeadline(host string, deadline time.Time) (addrs []IP, err error) { | 62 func lookupIPDeadline(host string, deadline time.Time) (addrs []IP, err error) { |
56 if deadline.IsZero() { | 63 if deadline.IsZero() { |
57 return lookupIPMerge(host) | 64 return lookupIPMerge(host) |
58 } | 65 } |
59 | 66 |
60 » // TODO(bradfitz): consider pushing the deadline down into the | 67 » // We could push the deadline down into the name resolution |
61 » // name resolution functions. But that involves fixing it for | 68 » // functions. However, the most commonly used implementation |
62 » // the native Go resolver, cgo, Windows, etc. | 69 » // calls getaddrinfo, which has no timeout. |
63 » // | 70 |
64 » // In the meantime, just use a goroutine. Most users affected | |
65 » // by http://golang.org/issue/2631 are due to TCP connections | |
66 » // to unresponsive hosts, not DNS. | |
67 timeout := deadline.Sub(time.Now()) | 71 timeout := deadline.Sub(time.Now()) |
68 if timeout <= 0 { | 72 if timeout <= 0 { |
69 » » err = errTimeout | 73 » » return nil, errTimeout |
70 » » return | |
71 } | 74 } |
72 t := time.NewTimer(timeout) | 75 t := time.NewTimer(timeout) |
73 defer t.Stop() | 76 defer t.Stop() |
74 » type res struct { | 77 |
75 » » addrs []IP | 78 » ch := lookupGroup.DoChan(host, func() (interface{}, error) { |
76 » » err error | 79 » » return lookupIP(host) |
77 » } | 80 » }) |
78 » resc := make(chan res, 1) | 81 |
79 » go func() { | |
80 » » a, err := lookupIPMerge(host) | |
81 » » resc <- res{a, err} | |
82 » }() | |
83 select { | 82 select { |
84 case <-t.C: | 83 case <-t.C: |
85 » » err = errTimeout | 84 » » // The DNS lookup timed out for some reason. Force |
86 » case r := <-resc: | 85 » » // future requests to start the DNS lookup again |
87 » » addrs, err = r.addrs, r.err | 86 » » // rather than waiting for the current lookup to |
| 87 » » // complete. See issue 8602. |
| 88 » » lookupGroup.Forget(host) |
| 89 |
| 90 » » return nil, errTimeout |
| 91 |
| 92 » case r := <-ch: |
| 93 » » return lookupIPReturn(r.v, r.err, r.shared) |
88 } | 94 } |
89 return | |
90 } | 95 } |
91 | 96 |
92 // LookupPort looks up the port for the given network and service. | 97 // LookupPort looks up the port for the given network and service. |
93 func LookupPort(network, service string) (port int, err error) { | 98 func LookupPort(network, service string) (port int, err error) { |
94 return lookupPort(network, service) | 99 return lookupPort(network, service) |
95 } | 100 } |
96 | 101 |
97 // LookupCNAME returns the canonical DNS host for the given name. | 102 // LookupCNAME returns the canonical DNS host for the given name. |
98 // Callers that do not care about the canonical name can call | 103 // Callers that do not care about the canonical name can call |
99 // LookupHost or LookupIP directly; both take care of resolving | 104 // LookupHost or LookupIP directly; both take care of resolving |
(...skipping 28 matching lines...) Expand all Loading... |
128 // LookupTXT returns the DNS TXT records for the given domain name. | 133 // LookupTXT returns the DNS TXT records for the given domain name. |
129 func LookupTXT(name string) (txt []string, err error) { | 134 func LookupTXT(name string) (txt []string, err error) { |
130 return lookupTXT(name) | 135 return lookupTXT(name) |
131 } | 136 } |
132 | 137 |
133 // LookupAddr performs a reverse lookup for the given address, returning a list | 138 // LookupAddr performs a reverse lookup for the given address, returning a list |
134 // of names mapping to that address. | 139 // of names mapping to that address. |
135 func LookupAddr(addr string) (name []string, err error) { | 140 func LookupAddr(addr string) (name []string, err error) { |
136 return lookupAddr(addr) | 141 return lookupAddr(addr) |
137 } | 142 } |
LEFT | RIGHT |