runtime: correct facilities names in s390 CPU support
[gcc.git] / libgo / go / 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 }