...
Run Format

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 NaCl, methods and functions related to
    14	// Interface are not implemented.
    15	
    16	// BUG(mikio): On DragonFly BSD, NetBSD, OpenBSD, Plan 9 and Solaris,
    17	// 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)
   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)
   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	func (zc *ipv6ZoneCache) update(ift []Interface) {
   191		zc.Lock()
   192		defer zc.Unlock()
   193		now := time.Now()
   194		if zc.lastFetched.After(now.Add(-60 * time.Second)) {
   195			return
   196		}
   197		zc.lastFetched = now
   198		if len(ift) == 0 {
   199			var err error
   200			if ift, err = interfaceTable(0); err != nil {
   201				return
   202			}
   203		}
   204		zc.toIndex = make(map[string]int, len(ift))
   205		zc.toName = make(map[int]string, len(ift))
   206		for _, ifi := range ift {
   207			zc.toIndex[ifi.Name] = ifi.Index
   208			if _, ok := zc.toName[ifi.Index]; !ok {
   209				zc.toName[ifi.Index] = ifi.Name
   210			}
   211		}
   212	}
   213	
   214	func zoneToString(zone int) string {
   215		if zone == 0 {
   216			return ""
   217		}
   218		zoneCache.update(nil)
   219		zoneCache.RLock()
   220		defer zoneCache.RUnlock()
   221		name, ok := zoneCache.toName[zone]
   222		if !ok {
   223			name = uitoa(uint(zone))
   224		}
   225		return name
   226	}
   227	
   228	func zoneToInt(zone string) int {
   229		if zone == "" {
   230			return 0
   231		}
   232		zoneCache.update(nil)
   233		zoneCache.RLock()
   234		defer zoneCache.RUnlock()
   235		index, ok := zoneCache.toIndex[zone]
   236		if !ok {
   237			index, _, _ = dtoi(zone)
   238		}
   239		return index
   240	}
   241	

View as plain text