summaryrefslogtreecommitdiff
path: root/libgo/go/net/interface.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/net/interface.go')
-rw-r--r--libgo/go/net/interface.go112
1 files changed, 103 insertions, 9 deletions
diff --git a/libgo/go/net/interface.go b/libgo/go/net/interface.go
index 9c7b5da8fe..b3297f249d 100644
--- a/libgo/go/net/interface.go
+++ b/libgo/go/net/interface.go
@@ -1,10 +1,20 @@
-// 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"
+)
+
+// BUG(mikio): On NaCl, methods and functions related to
+// Interface are not implemented.
+
+// BUG(mikio): On DragonFly BSD, NetBSD, OpenBSD, Plan 9 and Solaris,
+// the MulticastAddrs method of Interface is not implemented.
var (
errInvalidInterface = errors.New("invalid network interface")
@@ -15,7 +25,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
@@ -59,7 +69,8 @@ func (f Flags) String() string {
return s
}
-// Addrs returns interface addresses for a specific interface.
+// Addrs returns a list of unicast interface addresses for a specific
+// interface.
func (ifi *Interface) Addrs() ([]Addr, error) {
if ifi == nil {
return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
@@ -71,8 +82,8 @@ func (ifi *Interface) Addrs() ([]Addr, error) {
return ifat, err
}
-// MulticastAddrs returns multicast, joined group addresses for
-// a specific interface.
+// MulticastAddrs returns a list of multicast, joined group addresses
+// for a specific interface.
func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
if ifi == nil {
return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
@@ -88,13 +99,19 @@ 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}
+ }
+ if len(ift) != 0 {
+ zoneCache.update(ift)
}
- return ift, err
+ return ift, nil
}
-// InterfaceAddrs returns a list of the system's network interface
+// InterfaceAddrs returns a list of the system's unicast interface
// addresses.
+//
+// The returned list does not identify the associated interface; use
+// Interfaces and Interface.Addrs for more detail.
func InterfaceAddrs() ([]Addr, error) {
ifat, err := interfaceAddrTable(nil)
if err != nil {
@@ -104,6 +121,10 @@ func InterfaceAddrs() ([]Addr, error) {
}
// InterfaceByIndex returns the interface specified by index.
+//
+// On Solaris, it returns one of the logical network interfaces
+// sharing the logical data link; for more precision use
+// InterfaceByName.
func InterfaceByIndex(index int) (*Interface, error) {
if index <= 0 {
return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceIndex}
@@ -137,6 +158,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 +168,73 @@ 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.
+//
+// Multiple names sharing the index are managed by first-come
+// first-served basis for consistency.
+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
+ if _, ok := zc.toName[ifi.Index]; !ok {
+ 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)
+ }
+ return index
+}