OSDN Git Service

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