package socket
import (
"encoding/binary"
"errors"
"net"
"runtime"
"strconv"
"sync"
"time"
)
func marshalInetAddr(a net .Addr , b []byte ) int {
switch a := a .(type ) {
case *net .TCPAddr :
return marshalSockaddr (a .IP , a .Port , a .Zone , b )
case *net .UDPAddr :
return marshalSockaddr (a .IP , a .Port , a .Zone , b )
case *net .IPAddr :
return marshalSockaddr (a .IP , 0 , a .Zone , b )
default :
return 0
}
}
func marshalSockaddr(ip net .IP , port int , zone string , b []byte ) int {
if ip4 := ip .To4 (); ip4 != nil {
switch runtime .GOOS {
case "android" , "illumos" , "linux" , "solaris" , "windows" :
NativeEndian .PutUint16 (b [:2 ], uint16 (sysAF_INET ))
default :
b [0 ] = sizeofSockaddrInet4
b [1 ] = sysAF_INET
}
binary .BigEndian .PutUint16 (b [2 :4 ], uint16 (port ))
copy (b [4 :8 ], ip4 )
return sizeofSockaddrInet4
}
if ip6 := ip .To16 (); ip6 != nil && ip .To4 () == nil {
switch runtime .GOOS {
case "android" , "illumos" , "linux" , "solaris" , "windows" :
NativeEndian .PutUint16 (b [:2 ], uint16 (sysAF_INET6 ))
default :
b [0 ] = sizeofSockaddrInet6
b [1 ] = sysAF_INET6
}
binary .BigEndian .PutUint16 (b [2 :4 ], uint16 (port ))
copy (b [8 :24 ], ip6 )
if zone != "" {
NativeEndian .PutUint32 (b [24 :28 ], uint32 (zoneCache .index (zone )))
}
return sizeofSockaddrInet6
}
return 0
}
func parseInetAddr(b []byte , network string ) (net .Addr , error ) {
if len (b ) < 2 {
return nil , errors .New ("invalid address" )
}
var af int
switch runtime .GOOS {
case "android" , "illumos" , "linux" , "solaris" , "windows" :
af = int (NativeEndian .Uint16 (b [:2 ]))
default :
af = int (b [1 ])
}
var ip net .IP
var zone string
if af == sysAF_INET {
if len (b ) < sizeofSockaddrInet4 {
return nil , errors .New ("short address" )
}
ip = make (net .IP , net .IPv4len )
copy (ip , b [4 :8 ])
}
if af == sysAF_INET6 {
if len (b ) < sizeofSockaddrInet6 {
return nil , errors .New ("short address" )
}
ip = make (net .IP , net .IPv6len )
copy (ip , b [8 :24 ])
if id := int (NativeEndian .Uint32 (b [24 :28 ])); id > 0 {
zone = zoneCache .name (id )
}
}
switch network {
case "tcp" , "tcp4" , "tcp6" :
return &net .TCPAddr {IP : ip , Port : int (binary .BigEndian .Uint16 (b [2 :4 ])), Zone : zone }, nil
case "udp" , "udp4" , "udp6" :
return &net .UDPAddr {IP : ip , Port : int (binary .BigEndian .Uint16 (b [2 :4 ])), Zone : zone }, nil
default :
return &net .IPAddr {IP : ip , Zone : zone }, nil
}
}
type ipv6ZoneCache struct {
sync .RWMutex
lastFetched time .Time
toIndex map [string ]int
toName map [int ]string
}
var zoneCache = ipv6ZoneCache {
toIndex : make (map [string ]int ),
toName : make (map [int ]string ),
}
func (zc *ipv6ZoneCache ) update (ift []net .Interface , force bool ) (updated bool ) {
zc .Lock ()
defer zc .Unlock ()
now := time .Now ()
if !force && zc .lastFetched .After (now .Add (-60 *time .Second )) {
return false
}
zc .lastFetched = now
if len (ift ) == 0 {
var err error
if ift , err = net .Interfaces (); err != nil {
return false
}
}
zc .toIndex = make (map [string ]int , len (ift ))
zc .toName = make (map [int ]string , len (ift ))
for _ , ifi := range ift {
zc .toIndex [ifi .Name ] = ifi .Index
if _ , ok := zc .toName [ifi .Index ]; !ok {
zc .toName [ifi .Index ] = ifi .Name
}
}
return true
}
func (zc *ipv6ZoneCache ) name (zone int ) string {
updated := zoneCache .update (nil , false )
zoneCache .RLock ()
name , ok := zoneCache .toName [zone ]
zoneCache .RUnlock ()
if !ok && !updated {
zoneCache .update (nil , true )
zoneCache .RLock ()
name , ok = zoneCache .toName [zone ]
zoneCache .RUnlock ()
}
if !ok {
name = strconv .Itoa (zone )
}
return name
}
func (zc *ipv6ZoneCache ) index (zone string ) int {
updated := zoneCache .update (nil , false )
zoneCache .RLock ()
index , ok := zoneCache .toIndex [zone ]
zoneCache .RUnlock ()
if !ok && !updated {
zoneCache .update (nil , true )
zoneCache .RLock ()
index , ok = zoneCache .toIndex [zone ]
zoneCache .RUnlock ()
}
if !ok {
index , _ = strconv .Atoi (zone )
}
return index
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .