package net
import (
"errors"
"internal/itoa"
"sync"
"time"
_ "unsafe"
)
var (
errInvalidInterface = errors .New ("invalid network interface" )
errInvalidInterfaceIndex = errors .New ("invalid network interface index" )
errInvalidInterfaceName = errors .New ("invalid network interface name" )
errNoSuchInterface = errors .New ("no such network interface" )
errNoSuchMulticastInterface = errors .New ("no such multicast network interface" )
)
type Interface struct {
Index int
MTU int
Name string
HardwareAddr HardwareAddr
Flags Flags
}
type Flags uint
const (
FlagUp Flags = 1 << iota
FlagBroadcast
FlagLoopback
FlagPointToPoint
FlagMulticast
FlagRunning
)
var flagNames = []string {
"up" ,
"broadcast" ,
"loopback" ,
"pointtopoint" ,
"multicast" ,
"running" ,
}
func (f Flags ) String () string {
s := ""
for i , name := range flagNames {
if f &(1 <<uint (i )) != 0 {
if s != "" {
s += "|"
}
s += name
}
}
if s == "" {
s = "0"
}
return s
}
func (ifi *Interface ) Addrs () ([]Addr , error ) {
if ifi == nil {
return nil , &OpError {Op : "route" , Net : "ip+net" , Source : nil , Addr : nil , Err : errInvalidInterface }
}
ifat , err := interfaceAddrTable (ifi )
if err != nil {
err = &OpError {Op : "route" , Net : "ip+net" , Source : nil , Addr : nil , Err : err }
}
return ifat , err
}
func (ifi *Interface ) MulticastAddrs () ([]Addr , error ) {
if ifi == nil {
return nil , &OpError {Op : "route" , Net : "ip+net" , Source : nil , Addr : nil , Err : errInvalidInterface }
}
ifat , err := interfaceMulticastAddrTable (ifi )
if err != nil {
err = &OpError {Op : "route" , Net : "ip+net" , Source : nil , Addr : nil , Err : err }
}
return ifat , err
}
func Interfaces () ([]Interface , error ) {
ift , err := interfaceTable (0 )
if err != nil {
return nil , &OpError {Op : "route" , Net : "ip+net" , Source : nil , Addr : nil , Err : err }
}
if len (ift ) != 0 {
zoneCache .update (ift , false )
}
return ift , nil
}
func InterfaceAddrs () ([]Addr , error ) {
ifat , err := interfaceAddrTable (nil )
if err != nil {
err = &OpError {Op : "route" , Net : "ip+net" , Source : nil , Addr : nil , Err : err }
}
return ifat , err
}
func InterfaceByIndex (index int ) (*Interface , error ) {
if index <= 0 {
return nil , &OpError {Op : "route" , Net : "ip+net" , Source : nil , Addr : nil , Err : errInvalidInterfaceIndex }
}
ift , err := interfaceTable (index )
if err != nil {
return nil , &OpError {Op : "route" , Net : "ip+net" , Source : nil , Addr : nil , Err : err }
}
ifi , err := interfaceByIndex (ift , index )
if err != nil {
err = &OpError {Op : "route" , Net : "ip+net" , Source : nil , Addr : nil , Err : err }
}
return ifi , err
}
func interfaceByIndex(ift []Interface , index int ) (*Interface , error ) {
for _ , ifi := range ift {
if index == ifi .Index {
return &ifi , nil
}
}
return nil , errNoSuchInterface
}
func InterfaceByName (name string ) (*Interface , error ) {
if name == "" {
return nil , &OpError {Op : "route" , Net : "ip+net" , Source : nil , Addr : nil , Err : errInvalidInterfaceName }
}
ift , err := interfaceTable (0 )
if err != nil {
return nil , &OpError {Op : "route" , Net : "ip+net" , Source : nil , Addr : nil , Err : err }
}
if len (ift ) != 0 {
zoneCache .update (ift , false )
}
for _ , ifi := range ift {
if name == ifi .Name {
return &ifi , nil
}
}
return nil , &OpError {Op : "route" , Net : "ip+net" , Source : nil , Addr : nil , Err : errNoSuchInterface }
}
type ipv6ZoneCache struct {
sync .RWMutex
lastFetched time .Time
toIndex map [string ]int
toName map [int ]string
}
var zoneCache = ipv6ZoneCache {
toIndex : make (map [string ]int ),
toName : make (map [int ]string ),
}
func (zc *ipv6ZoneCache ) update (ift []Interface , force bool ) (updated bool ) {
zc .Lock ()
defer zc .Unlock ()
now := time .Now ()
if !force && zc .lastFetched .After (now .Add (-60 *time .Second )) {
return false
}
zc .lastFetched = now
if len (ift ) == 0 {
var err error
if ift , err = interfaceTable (0 ); err != nil {
return false
}
}
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
}
}
return true
}
func (zc *ipv6ZoneCache ) name (index int ) string {
if index == 0 {
return ""
}
updated := zoneCache .update (nil , false )
zoneCache .RLock ()
name , ok := zoneCache .toName [index ]
zoneCache .RUnlock ()
if !ok && !updated {
zoneCache .update (nil , true )
zoneCache .RLock ()
name , ok = zoneCache .toName [index ]
zoneCache .RUnlock ()
}
if !ok {
name = itoa .Uitoa (uint (index ))
}
return name
}
func (zc *ipv6ZoneCache ) index (name string ) int {
if name == "" {
return 0
}
updated := zoneCache .update (nil , false )
zoneCache .RLock ()
index , ok := zoneCache .toIndex [name ]
zoneCache .RUnlock ()
if !ok && !updated {
zoneCache .update (nil , true )
zoneCache .RLock ()
index , ok = zoneCache .toIndex [name ]
zoneCache .RUnlock ()
}
if !ok {
index , _, _ = dtoi (name )
}
return index
}
The pages are generated with Golds v0.7.0-preview . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .