Commit eb2e6e59 authored by Alex Brainman's avatar Alex Brainman

net: implement IPv6 support for windows

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
parent f8892fb3
......@@ -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
}
......
......@@ -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 {
......
......@@ -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 {
......
......@@ -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 {
......
......@@ -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
......
......@@ -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
}
......
......@@ -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
......
......@@ -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 {
......
......@@ -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 {
......
......@@ -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
)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment