diff options
Diffstat (limited to 'libgo/go/net/interface.go')
-rw-r--r-- | libgo/go/net/interface.go | 85 |
1 files changed, 80 insertions, 5 deletions
diff --git a/libgo/go/net/interface.go b/libgo/go/net/interface.go index 9c7b5da8fe9..52b857c65f1 100644 --- a/libgo/go/net/interface.go +++ b/libgo/go/net/interface.go @@ -1,10 +1,14 @@ -// Copyright 2011 The Go Authors. All rights reserved. +// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package net -import "errors" +import ( + "errors" + "sync" + "time" +) var ( errInvalidInterface = errors.New("invalid network interface") @@ -15,7 +19,7 @@ var ( ) // Interface represents a mapping between network interface name -// and index. It also represents network interface facility +// and index. It also represents network interface facility // information. type Interface struct { Index int // positive integer that starts at one, zero is never used @@ -88,9 +92,12 @@ func (ifi *Interface) MulticastAddrs() ([]Addr, error) { func Interfaces() ([]Interface, error) { ift, err := interfaceTable(0) if err != nil { - err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} + return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} } - return ift, err + if len(ift) != 0 { + zoneCache.update(ift) + } + return ift, nil } // InterfaceAddrs returns a list of the system's network interface @@ -137,6 +144,9 @@ func InterfaceByName(name string) (*Interface, error) { if err != nil { return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} } + if len(ift) != 0 { + zoneCache.update(ift) + } for _, ifi := range ift { if name == ifi.Name { return &ifi, nil @@ -144,3 +154,68 @@ func InterfaceByName(name string) (*Interface, error) { } return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errNoSuchInterface} } + +// An ipv6ZoneCache represents a cache holding partial network +// interface information. It is used for reducing the cost of IPv6 +// addressing scope zone resolution. +type ipv6ZoneCache struct { + sync.RWMutex // guard the following + lastFetched time.Time // last time routing information was fetched + toIndex map[string]int // interface name to its index + toName map[int]string // interface index to its name +} + +var zoneCache = ipv6ZoneCache{ + toIndex: make(map[string]int), + toName: make(map[int]string), +} + +func (zc *ipv6ZoneCache) update(ift []Interface) { + zc.Lock() + defer zc.Unlock() + now := time.Now() + if zc.lastFetched.After(now.Add(-60 * time.Second)) { + return + } + zc.lastFetched = now + if len(ift) == 0 { + var err error + if ift, err = interfaceTable(0); err != nil { + return + } + } + zc.toIndex = make(map[string]int, len(ift)) + zc.toName = make(map[int]string, len(ift)) + for _, ifi := range ift { + zc.toIndex[ifi.Name] = ifi.Index + zc.toName[ifi.Index] = ifi.Name + } +} + +func zoneToString(zone int) string { + if zone == 0 { + return "" + } + zoneCache.update(nil) + zoneCache.RLock() + defer zoneCache.RUnlock() + name, ok := zoneCache.toName[zone] + if !ok { + name = uitoa(uint(zone)) + } + return name +} + +func zoneToInt(zone string) int { + if zone == "" { + return 0 + } + zoneCache.update(nil) + zoneCache.RLock() + defer zoneCache.RUnlock() + index, ok := zoneCache.toIndex[zone] + if !ok { + index, _, _ = dtoi(zone, 0) + } + return index +} |