update packaging
[platform/core/system/edge-orchestration.git] / vendor / golang.org / x / net / internal / socket / sys_posix.go
1 // Copyright 2017 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 // +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
6
7 package socket
8
9 import (
10         "encoding/binary"
11         "errors"
12         "net"
13         "runtime"
14         "strconv"
15         "sync"
16         "time"
17 )
18
19 func marshalInetAddr(a net.Addr) []byte {
20         switch a := a.(type) {
21         case *net.TCPAddr:
22                 return marshalSockaddr(a.IP, a.Port, a.Zone)
23         case *net.UDPAddr:
24                 return marshalSockaddr(a.IP, a.Port, a.Zone)
25         case *net.IPAddr:
26                 return marshalSockaddr(a.IP, 0, a.Zone)
27         default:
28                 return nil
29         }
30 }
31
32 func marshalSockaddr(ip net.IP, port int, zone string) []byte {
33         if ip4 := ip.To4(); ip4 != nil {
34                 b := make([]byte, sizeofSockaddrInet)
35                 switch runtime.GOOS {
36                 case "android", "linux", "solaris", "windows":
37                         NativeEndian.PutUint16(b[:2], uint16(sysAF_INET))
38                 default:
39                         b[0] = sizeofSockaddrInet
40                         b[1] = sysAF_INET
41                 }
42                 binary.BigEndian.PutUint16(b[2:4], uint16(port))
43                 copy(b[4:8], ip4)
44                 return b
45         }
46         if ip6 := ip.To16(); ip6 != nil && ip.To4() == nil {
47                 b := make([]byte, sizeofSockaddrInet6)
48                 switch runtime.GOOS {
49                 case "android", "linux", "solaris", "windows":
50                         NativeEndian.PutUint16(b[:2], uint16(sysAF_INET6))
51                 default:
52                         b[0] = sizeofSockaddrInet6
53                         b[1] = sysAF_INET6
54                 }
55                 binary.BigEndian.PutUint16(b[2:4], uint16(port))
56                 copy(b[8:24], ip6)
57                 if zone != "" {
58                         NativeEndian.PutUint32(b[24:28], uint32(zoneCache.index(zone)))
59                 }
60                 return b
61         }
62         return nil
63 }
64
65 func parseInetAddr(b []byte, network string) (net.Addr, error) {
66         if len(b) < 2 {
67                 return nil, errors.New("invalid address")
68         }
69         var af int
70         switch runtime.GOOS {
71         case "android", "linux", "solaris", "windows":
72                 af = int(NativeEndian.Uint16(b[:2]))
73         default:
74                 af = int(b[1])
75         }
76         var ip net.IP
77         var zone string
78         if af == sysAF_INET {
79                 if len(b) < sizeofSockaddrInet {
80                         return nil, errors.New("short address")
81                 }
82                 ip = make(net.IP, net.IPv4len)
83                 copy(ip, b[4:8])
84         }
85         if af == sysAF_INET6 {
86                 if len(b) < sizeofSockaddrInet6 {
87                         return nil, errors.New("short address")
88                 }
89                 ip = make(net.IP, net.IPv6len)
90                 copy(ip, b[8:24])
91                 if id := int(NativeEndian.Uint32(b[24:28])); id > 0 {
92                         zone = zoneCache.name(id)
93                 }
94         }
95         switch network {
96         case "tcp", "tcp4", "tcp6":
97                 return &net.TCPAddr{IP: ip, Port: int(binary.BigEndian.Uint16(b[2:4])), Zone: zone}, nil
98         case "udp", "udp4", "udp6":
99                 return &net.UDPAddr{IP: ip, Port: int(binary.BigEndian.Uint16(b[2:4])), Zone: zone}, nil
100         default:
101                 return &net.IPAddr{IP: ip, Zone: zone}, nil
102         }
103 }
104
105 // An ipv6ZoneCache represents a cache holding partial network
106 // interface information. It is used for reducing the cost of IPv6
107 // addressing scope zone resolution.
108 //
109 // Multiple names sharing the index are managed by first-come
110 // first-served basis for consistency.
111 type ipv6ZoneCache struct {
112         sync.RWMutex                // guard the following
113         lastFetched  time.Time      // last time routing information was fetched
114         toIndex      map[string]int // interface name to its index
115         toName       map[int]string // interface index to its name
116 }
117
118 var zoneCache = ipv6ZoneCache{
119         toIndex: make(map[string]int),
120         toName:  make(map[int]string),
121 }
122
123 // update refreshes the network interface information if the cache was last
124 // updated more than 1 minute ago, or if force is set. It returns whether the
125 // cache was updated.
126 func (zc *ipv6ZoneCache) update(ift []net.Interface, force bool) (updated bool) {
127         zc.Lock()
128         defer zc.Unlock()
129         now := time.Now()
130         if !force && zc.lastFetched.After(now.Add(-60*time.Second)) {
131                 return false
132         }
133         zc.lastFetched = now
134         if len(ift) == 0 {
135                 var err error
136                 if ift, err = net.Interfaces(); err != nil {
137                         return false
138                 }
139         }
140         zc.toIndex = make(map[string]int, len(ift))
141         zc.toName = make(map[int]string, len(ift))
142         for _, ifi := range ift {
143                 zc.toIndex[ifi.Name] = ifi.Index
144                 if _, ok := zc.toName[ifi.Index]; !ok {
145                         zc.toName[ifi.Index] = ifi.Name
146                 }
147         }
148         return true
149 }
150
151 func (zc *ipv6ZoneCache) name(zone int) string {
152         updated := zoneCache.update(nil, false)
153         zoneCache.RLock()
154         name, ok := zoneCache.toName[zone]
155         zoneCache.RUnlock()
156         if !ok && !updated {
157                 zoneCache.update(nil, true)
158                 zoneCache.RLock()
159                 name, ok = zoneCache.toName[zone]
160                 zoneCache.RUnlock()
161         }
162         if !ok { // last resort
163                 name = strconv.Itoa(zone)
164         }
165         return name
166 }
167
168 func (zc *ipv6ZoneCache) index(zone string) int {
169         updated := zoneCache.update(nil, false)
170         zoneCache.RLock()
171         index, ok := zoneCache.toIndex[zone]
172         zoneCache.RUnlock()
173         if !ok && !updated {
174                 zoneCache.update(nil, true)
175                 zoneCache.RLock()
176                 index, ok = zoneCache.toIndex[zone]
177                 zoneCache.RUnlock()
178         }
179         if !ok { // last resort
180                 index, _ = strconv.Atoi(zone)
181         }
182         return index
183 }