/gcc/libgo/go/net/interface.go

https://github.com/haiku/buildtools · Go · 256 lines · 199 code · 22 blank · 35 comment · 57 complexity · 1de2210361240cb1b3b237a4bb5bdbf1 MD5 · raw file

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