mirror of
https://github.com/golang/go
synced 2024-11-20 02:54:39 -07:00
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
This commit is contained in:
parent
f8892fb395
commit
eb2e6e59ee
@ -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
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user