sys_posix.go 4.1 KB

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