...

Source file src/net/interface.go

Documentation: net

		 1  // Copyright 2011 The Go Authors. All rights reserved.
		 2  // Use of this source code is governed by a BSD-style
		 3  // license that can be found in the LICENSE file.
		 4  
		 5  package net
		 6  
		 7  import (
		 8  	"errors"
		 9  	"internal/itoa"
		10  	"sync"
		11  	"time"
		12  )
		13  
		14  // BUG(mikio): On JS, methods and functions related to
		15  // Interface are not implemented.
		16  
		17  // BUG(mikio): On AIX, DragonFly BSD, NetBSD, OpenBSD, Plan 9 and
		18  // Solaris, the MulticastAddrs method of Interface is not implemented.
		19  
		20  var (
		21  	errInvalidInterface				 = errors.New("invalid network interface")
		22  	errInvalidInterfaceIndex		= errors.New("invalid network interface index")
		23  	errInvalidInterfaceName		 = errors.New("invalid network interface name")
		24  	errNoSuchInterface					= errors.New("no such network interface")
		25  	errNoSuchMulticastInterface = errors.New("no such multicast network interface")
		26  )
		27  
		28  // Interface represents a mapping between network interface name
		29  // and index. It also represents network interface facility
		30  // information.
		31  type Interface struct {
		32  	Index				int					// positive integer that starts at one, zero is never used
		33  	MTU					int					// maximum transmission unit
		34  	Name				 string			 // e.g., "en0", "lo0", "eth0.100"
		35  	HardwareAddr HardwareAddr // IEEE MAC-48, EUI-48 and EUI-64 form
		36  	Flags				Flags				// e.g., FlagUp, FlagLoopback, FlagMulticast
		37  }
		38  
		39  type Flags uint
		40  
		41  const (
		42  	FlagUp					 Flags = 1 << iota // interface is up
		43  	FlagBroadcast											// interface supports broadcast access capability
		44  	FlagLoopback											 // interface is a loopback interface
		45  	FlagPointToPoint									 // interface belongs to a point-to-point link
		46  	FlagMulticast											// interface supports multicast access capability
		47  )
		48  
		49  var flagNames = []string{
		50  	"up",
		51  	"broadcast",
		52  	"loopback",
		53  	"pointtopoint",
		54  	"multicast",
		55  }
		56  
		57  func (f Flags) String() string {
		58  	s := ""
		59  	for i, name := range flagNames {
		60  		if f&(1<<uint(i)) != 0 {
		61  			if s != "" {
		62  				s += "|"
		63  			}
		64  			s += name
		65  		}
		66  	}
		67  	if s == "" {
		68  		s = "0"
		69  	}
		70  	return s
		71  }
		72  
		73  // Addrs returns a list of unicast interface addresses for a specific
		74  // interface.
		75  func (ifi *Interface) Addrs() ([]Addr, error) {
		76  	if ifi == nil {
		77  		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
		78  	}
		79  	ifat, err := interfaceAddrTable(ifi)
		80  	if err != nil {
		81  		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
		82  	}
		83  	return ifat, err
		84  }
		85  
		86  // MulticastAddrs returns a list of multicast, joined group addresses
		87  // for a specific interface.
		88  func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
		89  	if ifi == nil {
		90  		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
		91  	}
		92  	ifat, err := interfaceMulticastAddrTable(ifi)
		93  	if err != nil {
		94  		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
		95  	}
		96  	return ifat, err
		97  }
		98  
		99  // Interfaces returns a list of the system's network interfaces.
	 100  func Interfaces() ([]Interface, error) {
	 101  	ift, err := interfaceTable(0)
	 102  	if err != nil {
	 103  		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
	 104  	}
	 105  	if len(ift) != 0 {
	 106  		zoneCache.update(ift, false)
	 107  	}
	 108  	return ift, nil
	 109  }
	 110  
	 111  // InterfaceAddrs returns a list of the system's unicast interface
	 112  // addresses.
	 113  //
	 114  // The returned list does not identify the associated interface; use
	 115  // Interfaces and Interface.Addrs for more detail.
	 116  func InterfaceAddrs() ([]Addr, error) {
	 117  	ifat, err := interfaceAddrTable(nil)
	 118  	if err != nil {
	 119  		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
	 120  	}
	 121  	return ifat, err
	 122  }
	 123  
	 124  // InterfaceByIndex returns the interface specified by index.
	 125  //
	 126  // On Solaris, it returns one of the logical network interfaces
	 127  // sharing the logical data link; for more precision use
	 128  // InterfaceByName.
	 129  func InterfaceByIndex(index int) (*Interface, error) {
	 130  	if index <= 0 {
	 131  		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceIndex}
	 132  	}
	 133  	ift, err := interfaceTable(index)
	 134  	if err != nil {
	 135  		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
	 136  	}
	 137  	ifi, err := interfaceByIndex(ift, index)
	 138  	if err != nil {
	 139  		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
	 140  	}
	 141  	return ifi, err
	 142  }
	 143  
	 144  func interfaceByIndex(ift []Interface, index int) (*Interface, error) {
	 145  	for _, ifi := range ift {
	 146  		if index == ifi.Index {
	 147  			return &ifi, nil
	 148  		}
	 149  	}
	 150  	return nil, errNoSuchInterface
	 151  }
	 152  
	 153  // InterfaceByName returns the interface specified by name.
	 154  func InterfaceByName(name string) (*Interface, error) {
	 155  	if name == "" {
	 156  		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceName}
	 157  	}
	 158  	ift, err := interfaceTable(0)
	 159  	if err != nil {
	 160  		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
	 161  	}
	 162  	if len(ift) != 0 {
	 163  		zoneCache.update(ift, false)
	 164  	}
	 165  	for _, ifi := range ift {
	 166  		if name == ifi.Name {
	 167  			return &ifi, nil
	 168  		}
	 169  	}
	 170  	return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errNoSuchInterface}
	 171  }
	 172  
	 173  // An ipv6ZoneCache represents a cache holding partial network
	 174  // interface information. It is used for reducing the cost of IPv6
	 175  // addressing scope zone resolution.
	 176  //
	 177  // Multiple names sharing the index are managed by first-come
	 178  // first-served basis for consistency.
	 179  type ipv6ZoneCache struct {
	 180  	sync.RWMutex								// guard the following
	 181  	lastFetched	time.Time			// last time routing information was fetched
	 182  	toIndex			map[string]int // interface name to its index
	 183  	toName			 map[int]string // interface index to its name
	 184  }
	 185  
	 186  var zoneCache = ipv6ZoneCache{
	 187  	toIndex: make(map[string]int),
	 188  	toName:	make(map[int]string),
	 189  }
	 190  
	 191  // update refreshes the network interface information if the cache was last
	 192  // updated more than 1 minute ago, or if force is set. It reports whether the
	 193  // cache was updated.
	 194  func (zc *ipv6ZoneCache) update(ift []Interface, force bool) (updated bool) {
	 195  	zc.Lock()
	 196  	defer zc.Unlock()
	 197  	now := time.Now()
	 198  	if !force && zc.lastFetched.After(now.Add(-60*time.Second)) {
	 199  		return false
	 200  	}
	 201  	zc.lastFetched = now
	 202  	if len(ift) == 0 {
	 203  		var err error
	 204  		if ift, err = interfaceTable(0); err != nil {
	 205  			return false
	 206  		}
	 207  	}
	 208  	zc.toIndex = make(map[string]int, len(ift))
	 209  	zc.toName = make(map[int]string, len(ift))
	 210  	for _, ifi := range ift {
	 211  		zc.toIndex[ifi.Name] = ifi.Index
	 212  		if _, ok := zc.toName[ifi.Index]; !ok {
	 213  			zc.toName[ifi.Index] = ifi.Name
	 214  		}
	 215  	}
	 216  	return true
	 217  }
	 218  
	 219  func (zc *ipv6ZoneCache) name(index int) string {
	 220  	if index == 0 {
	 221  		return ""
	 222  	}
	 223  	updated := zoneCache.update(nil, false)
	 224  	zoneCache.RLock()
	 225  	name, ok := zoneCache.toName[index]
	 226  	zoneCache.RUnlock()
	 227  	if !ok && !updated {
	 228  		zoneCache.update(nil, true)
	 229  		zoneCache.RLock()
	 230  		name, ok = zoneCache.toName[index]
	 231  		zoneCache.RUnlock()
	 232  	}
	 233  	if !ok { // last resort
	 234  		name = itoa.Uitoa(uint(index))
	 235  	}
	 236  	return name
	 237  }
	 238  
	 239  func (zc *ipv6ZoneCache) index(name string) int {
	 240  	if name == "" {
	 241  		return 0
	 242  	}
	 243  	updated := zoneCache.update(nil, false)
	 244  	zoneCache.RLock()
	 245  	index, ok := zoneCache.toIndex[name]
	 246  	zoneCache.RUnlock()
	 247  	if !ok && !updated {
	 248  		zoneCache.update(nil, true)
	 249  		zoneCache.RLock()
	 250  		index, ok = zoneCache.toIndex[name]
	 251  		zoneCache.RUnlock()
	 252  	}
	 253  	if !ok { // last resort
	 254  		index, _, _ = dtoi(name)
	 255  	}
	 256  	return index
	 257  }
	 258  

View as plain text