]> Cypherpunks repositories - gostls13.git/commitdiff
net: implement IPv6 support for windows
authorAlex Brainman <alex.brainman@gmail.com>
Wed, 7 Nov 2012 05:58:20 +0000 (16:58 +1100)
committerAlex Brainman <alex.brainman@gmail.com>
Wed, 7 Nov 2012 05:58:20 +0000 (16:58 +1100)
Thank you zhoumichaely for original CL 5175042.

Fixes #1740.
Fixes #2315.

R=golang-dev, bradfitz, mikioh.mikioh
CC=golang-dev, zhoumichaely
https://golang.org/cl/6822045

src/pkg/net/dialgoogle_test.go
src/pkg/net/fd_unix.go
src/pkg/net/fd_windows.go
src/pkg/net/ipsock.go
src/pkg/net/ipsock_plan9.go
src/pkg/net/lookup_windows.go
src/pkg/syscall/syscall_windows.go
src/pkg/syscall/zsyscall_windows_386.go
src/pkg/syscall/zsyscall_windows_amd64.go
src/pkg/syscall/ztypes_windows.go

index 426e2ffb0017e33c4877f5139947949931a639ac..dd3c4ba7e156cf368147776b222d97ddd405c5cc 100644 (file)
@@ -116,7 +116,12 @@ func TestDialGoogleIPv6(t *testing.T) {
                return
        }
        // Only run tcp6 if the kernel will take it.
-       if !*testIPv6 || !supportsIPv6 {
+       if !supportsIPv6 {
+               t.Logf("skipping test; ipv6 is not supported")
+               return
+       }
+       if !*testIPv6 {
+               t.Logf("test disabled; use -ipv6 to enable")
                return
        }
 
index ee82ead0266c75f0a85dca8432ac60af1a656e66..e1d1256fa1d116397e21eed789a8eb41ad46f6d8 100644 (file)
@@ -262,6 +262,9 @@ var startServersOnce []func()
 
 var canCancelIO = true // used for testing current package
 
+func sysInit() {
+}
+
 func init() {
        pollMaxN = runtime.NumCPU()
        if pollMaxN > 8 {
index 5f4312589212e1b54ee72ff422000f17b5413a78..5338def92205be12bad90de2b038eb14d132e63d 100644 (file)
@@ -29,13 +29,16 @@ var initErr error
 
 var canCancelIO bool // determines if CancelIoEx API is present
 
-func init() {
+func sysInit() {
        var d syscall.WSAData
        e := syscall.WSAStartup(uint32(0x202), &d)
        if e != nil {
                initErr = os.NewSyscallError("WSAStartup", e)
        }
        canCancelIO = syscall.LoadCancelIoEx() == nil
+       if syscall.LoadGetAddrInfo() == nil {
+               lookupIP = newLookupIP
+       }
 }
 
 func closesocket(s syscall.Handle) error {
index 84547c7a6a8ea537e83819d0230cf6b4a085ad51..b9b2a9b81ecc54759bb93175321b702f70f42b86 100644 (file)
@@ -6,7 +6,12 @@
 
 package net
 
-var supportsIPv6, supportsIPv4map = probeIPv6Stack()
+var supportsIPv6, supportsIPv4map bool
+
+func init() {
+       sysInit()
+       supportsIPv6, supportsIPv4map = probeIPv6Stack()
+}
 
 func firstFavoriteAddr(filter func(IP) IP, addrs []string) (addr IP) {
        if filter == nil {
index f5be54cb2ac28f6a8c3d0975909bf1afff4f761a..4111acfc2e110f34bae98ca290fe23e64681991d 100644 (file)
@@ -26,6 +26,9 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
 
 var canCancelIO = true // used for testing current package
 
+func sysInit() {
+}
+
 // parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
 func parsePlan9Addr(s string) (ip IP, iport int, err error) {
        addr := IPv4zero // address contains port only
index 2a8d01ff40a4596a8f7aa6cc2b9d86dc198c2bc8..390fe7f4405e6ea0fb7ce1a6273e9e7338fcf688 100644 (file)
@@ -40,7 +40,9 @@ func lookupHost(name string) (addrs []string, err error) {
        return
 }
 
-func lookupIP(name string) (addrs []IP, err error) {
+var lookupIP = oldLookupIP
+
+func oldLookupIP(name string) (addrs []IP, err error) {
        hostentLock.Lock()
        defer hostentLock.Unlock()
        h, err := syscall.GetHostByName(name)
@@ -56,7 +58,36 @@ func lookupIP(name string) (addrs []IP, err error) {
                }
                addrs = addrs[0:i]
        default: // TODO(vcc): Implement non IPv4 address lookups.
-               return nil, os.NewSyscallError("LookupHost", syscall.EWINDOWS)
+               return nil, os.NewSyscallError("LookupIP", syscall.EWINDOWS)
+       }
+       return addrs, nil
+}
+
+func newLookupIP(name string) (addrs []IP, err error) {
+       hints := syscall.AddrinfoW{
+               Family:   syscall.AF_UNSPEC,
+               Socktype: syscall.SOCK_STREAM,
+               Protocol: syscall.IPPROTO_IP,
+       }
+       var result *syscall.AddrinfoW
+       e := syscall.GetAddrInfoW(syscall.StringToUTF16Ptr(name), nil, &hints, &result)
+       if e != nil {
+               return nil, os.NewSyscallError("GetAddrInfoW", e)
+       }
+       defer syscall.FreeAddrInfoW(result)
+       addrs = make([]IP, 0, 5)
+       for ; result != nil; result = result.Next {
+               addr := unsafe.Pointer(result.Addr)
+               switch result.Family {
+               case syscall.AF_INET:
+                       a := (*syscall.RawSockaddrInet4)(addr).Addr
+                       addrs = append(addrs, IPv4(a[0], a[1], a[2], a[3]))
+               case syscall.AF_INET6:
+                       a := (*syscall.RawSockaddrInet6)(addr).Addr
+                       addrs = append(addrs, IP{a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]})
+               default:
+                       return nil, os.NewSyscallError("LookupIP", syscall.EWINDOWS)
+               }
        }
        return addrs, nil
 }
index 535bd55466552303e68a0027390f4a8622fca39c..9fe2da385ab4a9df100df1de8bee4040be4c3e60 100644 (file)
@@ -508,6 +508,8 @@ const socket_error = uintptr(^uint32(0))
 //sys  GetProtoByName(name string) (p *Protoent, err error) [failretval==nil] = ws2_32.getprotobyname
 //sys  DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) = dnsapi.DnsQuery_W
 //sys  DnsRecordListFree(rl *DNSRecord, freetype uint32) = dnsapi.DnsRecordListFree
+//sys  GetAddrInfoW(nodename *uint16, servicename *uint16, hints *AddrinfoW, result **AddrinfoW) (sockerr error) = ws2_32.GetAddrInfoW
+//sys  FreeAddrInfoW(addrinfo *AddrinfoW) = ws2_32.FreeAddrInfoW
 //sys  GetIfEntry(pIfRow *MibIfRow) (errcode error) = iphlpapi.GetIfEntry
 //sys  GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) = iphlpapi.GetAdaptersInfo
 
@@ -522,6 +524,14 @@ type RawSockaddrInet4 struct {
        Zero   [8]uint8
 }
 
+type RawSockaddrInet6 struct {
+       Family   uint16
+       Port     uint16
+       Flowinfo uint32
+       Addr     [16]byte /* in6_addr */
+       Scope_id uint32
+}
+
 type RawSockaddr struct {
        Family uint16
        Data   [14]int8
@@ -560,11 +570,22 @@ type SockaddrInet6 struct {
        Port   int
        ZoneId uint32
        Addr   [16]byte
+       raw    RawSockaddrInet6
 }
 
 func (sa *SockaddrInet6) sockaddr() (uintptr, int32, error) {
-       // TODO(brainman): implement SockaddrInet6.sockaddr()
-       return 0, 0, EWINDOWS
+       if sa.Port < 0 || sa.Port > 0xFFFF {
+               return 0, 0, EINVAL
+       }
+       sa.raw.Family = AF_INET6
+       p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
+       p[0] = byte(sa.Port >> 8)
+       p[1] = byte(sa.Port)
+       sa.raw.Scope_id = sa.ZoneId
+       for i := 0; i < len(sa.Addr); i++ {
+               sa.raw.Addr[i] = sa.Addr[i]
+       }
+       return uintptr(unsafe.Pointer(&sa.raw)), int32(unsafe.Sizeof(sa.raw)), nil
 }
 
 type SockaddrUnix struct {
@@ -592,7 +613,15 @@ func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) {
                return sa, nil
 
        case AF_INET6:
-               return nil, EWINDOWS
+               pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))
+               sa := new(SockaddrInet6)
+               p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+               sa.Port = int(p[0])<<8 + int(p[1])
+               sa.ZoneId = pp.Scope_id
+               for i := 0; i < len(sa.Addr); i++ {
+                       sa.Addr[i] = pp.Addr[i]
+               }
+               return sa, nil
        }
        return nil, EAFNOSUPPORT
 }
@@ -659,6 +688,10 @@ func WSASendto(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32
        return WSASendTo(s, bufs, bufcnt, sent, flags, (*RawSockaddrAny)(unsafe.Pointer(rsa)), l, overlapped, croutine)
 }
 
+func LoadGetAddrInfo() error {
+       return procGetAddrInfoW.Find()
+}
+
 // Invented structures to support what package os expects.
 type Rusage struct {
        CreationTime Filetime
index debe3cd59602a8737cc5e62716636319ddc2357f..c90cdfc065a11f877705d56030fe8c0f00257340 100644 (file)
@@ -132,6 +132,8 @@ var (
        procgetprotobyname                   = modws2_32.NewProc("getprotobyname")
        procDnsQuery_W                       = moddnsapi.NewProc("DnsQuery_W")
        procDnsRecordListFree                = moddnsapi.NewProc("DnsRecordListFree")
+       procGetAddrInfoW                     = modws2_32.NewProc("GetAddrInfoW")
+       procFreeAddrInfoW                    = modws2_32.NewProc("FreeAddrInfoW")
        procGetIfEntry                       = modiphlpapi.NewProc("GetIfEntry")
        procGetAdaptersInfo                  = modiphlpapi.NewProc("GetAdaptersInfo")
        procTranslateNameW                   = modsecur32.NewProc("TranslateNameW")
@@ -1537,6 +1539,19 @@ func DnsRecordListFree(rl *DNSRecord, freetype uint32) {
        return
 }
 
+func GetAddrInfoW(nodename *uint16, servicename *uint16, hints *AddrinfoW, result **AddrinfoW) (sockerr error) {
+       r0, _, _ := Syscall6(procGetAddrInfoW.Addr(), 4, uintptr(unsafe.Pointer(nodename)), uintptr(unsafe.Pointer(servicename)), uintptr(unsafe.Pointer(hints)), uintptr(unsafe.Pointer(result)), 0, 0)
+       if r0 != 0 {
+               sockerr = Errno(r0)
+       }
+       return
+}
+
+func FreeAddrInfoW(addrinfo *AddrinfoW) {
+       Syscall(procFreeAddrInfoW.Addr(), 1, uintptr(unsafe.Pointer(addrinfo)), 0, 0)
+       return
+}
+
 func GetIfEntry(pIfRow *MibIfRow) (errcode error) {
        r0, _, _ := Syscall(procGetIfEntry.Addr(), 1, uintptr(unsafe.Pointer(pIfRow)), 0, 0)
        if r0 != 0 {
index 5a7e74c64552c921671ea10cf9b7943acfde505b..105fdda5841afccefc4c8bb1c89b76ebafa24891 100644 (file)
@@ -132,6 +132,8 @@ var (
        procgetprotobyname                   = modws2_32.NewProc("getprotobyname")
        procDnsQuery_W                       = moddnsapi.NewProc("DnsQuery_W")
        procDnsRecordListFree                = moddnsapi.NewProc("DnsRecordListFree")
+       procGetAddrInfoW                     = modws2_32.NewProc("GetAddrInfoW")
+       procFreeAddrInfoW                    = modws2_32.NewProc("FreeAddrInfoW")
        procGetIfEntry                       = modiphlpapi.NewProc("GetIfEntry")
        procGetAdaptersInfo                  = modiphlpapi.NewProc("GetAdaptersInfo")
        procTranslateNameW                   = modsecur32.NewProc("TranslateNameW")
@@ -1537,6 +1539,19 @@ func DnsRecordListFree(rl *DNSRecord, freetype uint32) {
        return
 }
 
+func GetAddrInfoW(nodename *uint16, servicename *uint16, hints *AddrinfoW, result **AddrinfoW) (sockerr error) {
+       r0, _, _ := Syscall6(procGetAddrInfoW.Addr(), 4, uintptr(unsafe.Pointer(nodename)), uintptr(unsafe.Pointer(servicename)), uintptr(unsafe.Pointer(hints)), uintptr(unsafe.Pointer(result)), 0, 0)
+       if r0 != 0 {
+               sockerr = Errno(r0)
+       }
+       return
+}
+
+func FreeAddrInfoW(addrinfo *AddrinfoW) {
+       Syscall(procFreeAddrInfoW.Addr(), 1, uintptr(unsafe.Pointer(addrinfo)), 0, 0)
+       return
+}
+
 func GetIfEntry(pIfRow *MibIfRow) (errcode error) {
        r0, _, _ := Syscall(procGetIfEntry.Addr(), 1, uintptr(unsafe.Pointer(pIfRow)), 0, 0)
        if r0 != 0 {
index 9827e129c04caf7261060b3954c3afb77bfdbbf7..1f7308796fbb25295b9a01e6402f984c325a00b5 100644 (file)
@@ -924,3 +924,20 @@ const (
        REG_DWORD = REG_DWORD_LITTLE_ENDIAN
        REG_QWORD = REG_QWORD_LITTLE_ENDIAN
 )
+
+type AddrinfoW struct {
+       Flags     int32
+       Family    int32
+       Socktype  int32
+       Protocol  int32
+       Addrlen   uintptr
+       Canonname *uint16
+       Addr      uintptr
+       Next      *AddrinfoW
+}
+
+const (
+       AI_PASSIVE     = 1
+       AI_CANONNAME   = 2
+       AI_NUMERICHOST = 4
+)