...

Source file src/net/interface.go

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

View as plain text