github.com/keysonZZZ/kmg@v0.0.0-20151121023212-05317bfd7d39/kmgNet/kmgUnix/sockaddr_unix.go (about)

     1  // +build darwin dragonfly freebsd linux netbsd openbsd solaris
     2  
     3  package kmgUnix
     4  
     5  import (
     6  	"net"
     7  
     8  	"golang.org/x/sys/unix"
     9  )
    10  
    11  func IPv4TcpAddrToUnixSocksAddr(addr string) (sa unix.Sockaddr, err error) {
    12  	tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
    13  	if err != nil {
    14  		return nil, err
    15  	}
    16  	return ipToSocksAddr(unix.AF_INET, tcpAddr.IP, tcpAddr.Port, tcpAddr.Zone)
    17  }
    18  
    19  //copy from http://golang.org/src/net/ipsock_posix.go?s=4615:4700#L130
    20  func ipToSocksAddr(family int, ip net.IP, port int, zone string) (unix.Sockaddr, error) {
    21  	switch family {
    22  	case unix.AF_INET:
    23  		if len(ip) == 0 {
    24  			ip = net.IPv4zero
    25  		}
    26  		if ip = ip.To4(); ip == nil {
    27  			return nil, net.InvalidAddrError("non-IPv4 address")
    28  		}
    29  		sa := new(unix.SockaddrInet4)
    30  		for i := 0; i < net.IPv4len; i++ {
    31  			sa.Addr[i] = ip[i]
    32  		}
    33  		sa.Port = port
    34  		return sa, nil
    35  	case unix.AF_INET6:
    36  		if len(ip) == 0 {
    37  			ip = net.IPv6zero
    38  		}
    39  		// IPv4 callers use 0.0.0.0 to mean "announce on any available address".
    40  		// In IPv6 mode, Linux treats that as meaning "announce on 0.0.0.0",
    41  		// which it refuses to do.  Rewrite to the IPv6 unspecified address.
    42  		if ip.Equal(net.IPv4zero) {
    43  			ip = net.IPv6zero
    44  		}
    45  		if ip = ip.To16(); ip == nil {
    46  			return nil, net.InvalidAddrError("non-IPv6 address")
    47  		}
    48  		sa := new(unix.SockaddrInet6)
    49  		for i := 0; i < net.IPv6len; i++ {
    50  			sa.Addr[i] = ip[i]
    51  		}
    52  		sa.Port = port
    53  		sa.ZoneId = uint32(zoneToInt(zone))
    54  		return sa, nil
    55  	}
    56  	return nil, net.InvalidAddrError("unexpected socket family")
    57  }
    58  
    59  func zoneToInt(zone string) int {
    60  	if zone == "" {
    61  		return 0
    62  	}
    63  	if ifi, err := net.InterfaceByName(zone); err == nil {
    64  		return ifi.Index
    65  	}
    66  	n, _, _ := dtoi(zone, 0)
    67  	return n
    68  }
    69  
    70  const big = 0xFFFFFF
    71  
    72  func dtoi(s string, i0 int) (n int, i int, ok bool) {
    73  	n = 0
    74  	for i = i0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
    75  		n = n*10 + int(s[i]-'0')
    76  		if n >= big {
    77  			return 0, i, false
    78  		}
    79  	}
    80  	if i == i0 {
    81  		return 0, i, false
    82  	}
    83  	return n, i, true
    84  }