net: redo resolv.conf recheck implementation

The previous implementation spawned an extra goroutine to handle
rechecking resolv.conf for changes.

This change eliminates the extra goroutine, and has rechecking
done as part of a lookup.  A side effect of this change is that the
first lookup after a resolv.conf change will now succeed, whereas
previously it would have failed.  It also fixes rechecking logic to
ignore resolv.conf parsing errors as it should.

Fixes #8652
Fixes #10576
Fixes #10649
Fixes #10650
Fixes #10845

Change-Id: I502b587c445fa8eca5207ca4f2c8ec8c339fec7f
Reviewed-on: https://go-review.googlesource.com/9991
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
Reviewed-by: Mikio Hara <mikioh.mikioh@gmail.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Alex A Skinner 2015-05-12 23:56:56 -04:00 committed by Brad Fitzpatrick
parent 40fad6c286
commit ef7e108565
2 changed files with 74 additions and 83 deletions

View file

@ -94,10 +94,8 @@ func TestSpecialDomainName(t *testing.T) {
type resolvConfTest struct {
*testing.T
dir string
path string
started bool
quitc chan chan struct{}
dir string
path string
}
func newResolvConfTest(t *testing.T) *resolvConfTest {
@ -106,24 +104,15 @@ func newResolvConfTest(t *testing.T) *resolvConfTest {
t.Fatal(err)
}
// Disable the default loadConfig
onceLoadConfig.Do(func() {})
r := &resolvConfTest{
T: t,
dir: dir,
path: path.Join(dir, "resolv.conf"),
quitc: make(chan chan struct{}),
T: t,
dir: dir,
path: path.Join(dir, "resolv.conf"),
}
return r
}
func (r *resolvConfTest) Start() {
loadConfig(r.path, 100*time.Millisecond, r.quitc)
r.started = true
}
func (r *resolvConfTest) SetConf(s string) {
// Make sure the file mtime will be different once we're done here,
// even on systems with coarse (1s) mtime resolution.
@ -138,12 +127,8 @@ func (r *resolvConfTest) SetConf(s string) {
r.Fatalf("failed to write temp file: %v", err)
}
f.Close()
if r.started {
cfg.ch <- struct{}{} // fill buffer
cfg.ch <- struct{}{} // wait for reload to begin
cfg.ch <- struct{}{} // wait for reload to complete
}
cfg.lastChecked = time.Time{}
loadConfig(r.path)
}
func (r *resolvConfTest) WantServers(want []string) {
@ -155,9 +140,6 @@ func (r *resolvConfTest) WantServers(want []string) {
}
func (r *resolvConfTest) Close() {
resp := make(chan struct{})
r.quitc <- resp
<-resp
if err := os.RemoveAll(r.dir); err != nil {
r.Logf("failed to remove temp dir %s: %v", r.dir, err)
}
@ -171,7 +153,6 @@ func TestReloadResolvConfFail(t *testing.T) {
r := newResolvConfTest(t)
defer r.Close()
r.Start()
r.SetConf("nameserver 8.8.8.8")
if _, err := goLookupIP("golang.org"); err != nil {
@ -200,7 +181,6 @@ func TestReloadResolvConfChange(t *testing.T) {
r := newResolvConfTest(t)
defer r.Close()
r.Start()
r.SetConf("nameserver 8.8.8.8")
if _, err := goLookupIP("golang.org"); err != nil {
@ -245,14 +225,14 @@ func BenchmarkGoLookupIPNoSuchHost(b *testing.B) {
func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) {
testHookUninstaller.Do(uninstallTestHooks)
onceLoadConfig.Do(loadDefaultConfig)
// This looks ugly but it's safe as long as benchmarks are run
// sequentially in package testing.
<-cfg.ch // keep config from being reloaded upon lookup
orig := cfg.dnsConfig
cfg.dnsConfig.servers = append([]string{"203.0.113.254"}, cfg.dnsConfig.servers...) // use TEST-NET-3 block, see RFC 5737
for i := 0; i < b.N; i++ {
goLookupIP("www.example.com")
}
cfg.dnsConfig = orig
cfg.ch <- struct{}{}
}