diff options
Diffstat (limited to 'libgo/go/net/hosts.go')
-rw-r--r-- | libgo/go/net/hosts.go | 95 |
1 files changed, 62 insertions, 33 deletions
diff --git a/libgo/go/net/hosts.go b/libgo/go/net/hosts.go index 27958c7cc50..c4de1b6a972 100644 --- a/libgo/go/net/hosts.go +++ b/libgo/go/net/hosts.go @@ -9,7 +9,7 @@ import ( "time" ) -const cacheMaxAge = 5 * time.Minute +const cacheMaxAge = 5 * time.Second func parseLiteralIP(addr string) string { var ip IP @@ -27,51 +27,76 @@ func parseLiteralIP(addr string) string { return ip.String() + "%" + zone } -// Simple cache. +// hosts contains known host entries. var hosts struct { sync.Mutex + + // Key for the list of literal IP addresses must be a host + // name. It would be part of DNS labels, a FQDN or an absolute + // FQDN. + // For now the key is converted to lower case for convenience. byName map[string][]string + + // Key for the list of host names must be a literal IP address + // including IPv6 address with zone identifier. + // We don't support old-classful IP address notation. byAddr map[string][]string + expire time.Time path string + mtime time.Time + size int64 } func readHosts() { now := time.Now() hp := testHookHostsPath - if len(hosts.byName) == 0 || now.After(hosts.expire) || hosts.path != hp { - hs := make(map[string][]string) - is := make(map[string][]string) - var file *file - if file, _ = open(hp); file == nil { - return + + if now.Before(hosts.expire) && hosts.path == hp && len(hosts.byName) > 0 { + return + } + mtime, size, err := stat(hp) + if err == nil && hosts.path == hp && hosts.mtime.Equal(mtime) && hosts.size == size { + hosts.expire = now.Add(cacheMaxAge) + return + } + + hs := make(map[string][]string) + is := make(map[string][]string) + var file *file + if file, _ = open(hp); file == nil { + return + } + for line, ok := file.readLine(); ok; line, ok = file.readLine() { + if i := byteIndex(line, '#'); i >= 0 { + // Discard comments. + line = line[0:i] } - for line, ok := file.readLine(); ok; line, ok = file.readLine() { - if i := byteIndex(line, '#'); i >= 0 { - // Discard comments. - line = line[0:i] - } - f := getFields(line) - if len(f) < 2 { - continue - } - addr := parseLiteralIP(f[0]) - if addr == "" { - continue - } - for i := 1; i < len(f); i++ { - h := f[i] - hs[h] = append(hs[h], addr) - is[addr] = append(is[addr], h) - } + f := getFields(line) + if len(f) < 2 { + continue + } + addr := parseLiteralIP(f[0]) + if addr == "" { + continue + } + for i := 1; i < len(f); i++ { + name := absDomainName([]byte(f[i])) + h := []byte(f[i]) + lowerASCIIBytes(h) + key := absDomainName(h) + hs[key] = append(hs[key], addr) + is[addr] = append(is[addr], name) } - // Update the data cache. - hosts.expire = now.Add(cacheMaxAge) - hosts.path = hp - hosts.byName = hs - hosts.byAddr = is - file.close() } + // Update the data cache. + hosts.expire = now.Add(cacheMaxAge) + hosts.path = hp + hosts.byName = hs + hosts.byAddr = is + hosts.mtime = mtime + hosts.size = size + file.close() } // lookupStaticHost looks up the addresses for the given host from /etc/hosts. @@ -80,7 +105,11 @@ func lookupStaticHost(host string) []string { defer hosts.Unlock() readHosts() if len(hosts.byName) != 0 { - if ips, ok := hosts.byName[host]; ok { + // TODO(jbd,bradfitz): avoid this alloc if host is already all lowercase? + // or linear scan the byName map if it's small enough? + lowerHost := []byte(host) + lowerASCIIBytes(lowerHost) + if ips, ok := hosts.byName[absDomainName(lowerHost)]; ok { return ips } } |