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.
5 // +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
19 func marshalInetAddr(a net.Addr) []byte {
20 switch a := a.(type) {
22 return marshalSockaddr(a.IP, a.Port, a.Zone)
24 return marshalSockaddr(a.IP, a.Port, a.Zone)
26 return marshalSockaddr(a.IP, 0, a.Zone)
32 func marshalSockaddr(ip net.IP, port int, zone string) []byte {
33 if ip4 := ip.To4(); ip4 != nil {
34 b := make([]byte, sizeofSockaddrInet)
36 case "android", "linux", "solaris", "windows":
37 NativeEndian.PutUint16(b[:2], uint16(sysAF_INET))
39 b[0] = sizeofSockaddrInet
42 binary.BigEndian.PutUint16(b[2:4], uint16(port))
46 if ip6 := ip.To16(); ip6 != nil && ip.To4() == nil {
47 b := make([]byte, sizeofSockaddrInet6)
49 case "android", "linux", "solaris", "windows":
50 NativeEndian.PutUint16(b[:2], uint16(sysAF_INET6))
52 b[0] = sizeofSockaddrInet6
55 binary.BigEndian.PutUint16(b[2:4], uint16(port))
58 NativeEndian.PutUint32(b[24:28], uint32(zoneCache.index(zone)))
65 func parseInetAddr(b []byte, network string) (net.Addr, error) {
67 return nil, errors.New("invalid address")
71 case "android", "linux", "solaris", "windows":
72 af = int(NativeEndian.Uint16(b[:2]))
79 if len(b) < sizeofSockaddrInet {
80 return nil, errors.New("short address")
82 ip = make(net.IP, net.IPv4len)
85 if af == sysAF_INET6 {
86 if len(b) < sizeofSockaddrInet6 {
87 return nil, errors.New("short address")
89 ip = make(net.IP, net.IPv6len)
91 if id := int(NativeEndian.Uint32(b[24:28])); id > 0 {
92 zone = zoneCache.name(id)
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
101 return &net.IPAddr{IP: ip, Zone: zone}, nil
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.
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
118 var zoneCache = ipv6ZoneCache{
119 toIndex: make(map[string]int),
120 toName: make(map[int]string),
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) {
130 if !force && zc.lastFetched.After(now.Add(-60*time.Second)) {
136 if ift, err = net.Interfaces(); err != nil {
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
151 func (zc *ipv6ZoneCache) name(zone int) string {
152 updated := zoneCache.update(nil, false)
154 name, ok := zoneCache.toName[zone]
157 zoneCache.update(nil, true)
159 name, ok = zoneCache.toName[zone]
162 if !ok { // last resort
163 name = strconv.Itoa(zone)
168 func (zc *ipv6ZoneCache) index(zone string) int {
169 updated := zoneCache.update(nil, false)
171 index, ok := zoneCache.toIndex[zone]
174 zoneCache.update(nil, true)
176 index, ok = zoneCache.toIndex[zone]
179 if !ok { // last resort
180 index, _ = strconv.Atoi(zone)