mirror of
https://github.com/golang/go
synced 2024-11-20 05:34:40 -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
|
return
|
||||||
}
|
}
|
||||||
// Only run tcp6 if the kernel will take it.
|
// 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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,6 +262,9 @@ var startServersOnce []func()
|
|||||||
|
|
||||||
var canCancelIO = true // used for testing current package
|
var canCancelIO = true // used for testing current package
|
||||||
|
|
||||||
|
func sysInit() {
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
pollMaxN = runtime.NumCPU()
|
pollMaxN = runtime.NumCPU()
|
||||||
if pollMaxN > 8 {
|
if pollMaxN > 8 {
|
||||||
|
@ -29,13 +29,16 @@ var initErr error
|
|||||||
|
|
||||||
var canCancelIO bool // determines if CancelIoEx API is present
|
var canCancelIO bool // determines if CancelIoEx API is present
|
||||||
|
|
||||||
func init() {
|
func sysInit() {
|
||||||
var d syscall.WSAData
|
var d syscall.WSAData
|
||||||
e := syscall.WSAStartup(uint32(0x202), &d)
|
e := syscall.WSAStartup(uint32(0x202), &d)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
initErr = os.NewSyscallError("WSAStartup", e)
|
initErr = os.NewSyscallError("WSAStartup", e)
|
||||||
}
|
}
|
||||||
canCancelIO = syscall.LoadCancelIoEx() == nil
|
canCancelIO = syscall.LoadCancelIoEx() == nil
|
||||||
|
if syscall.LoadGetAddrInfo() == nil {
|
||||||
|
lookupIP = newLookupIP
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func closesocket(s syscall.Handle) error {
|
func closesocket(s syscall.Handle) error {
|
||||||
|
@ -6,7 +6,12 @@
|
|||||||
|
|
||||||
package net
|
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) {
|
func firstFavoriteAddr(filter func(IP) IP, addrs []string) (addr IP) {
|
||||||
if filter == nil {
|
if filter == nil {
|
||||||
|
@ -26,6 +26,9 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
|
|||||||
|
|
||||||
var canCancelIO = true // used for testing current package
|
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).
|
// 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) {
|
func parsePlan9Addr(s string) (ip IP, iport int, err error) {
|
||||||
addr := IPv4zero // address contains port only
|
addr := IPv4zero // address contains port only
|
||||||
|
@ -40,7 +40,9 @@ func lookupHost(name string) (addrs []string, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func lookupIP(name string) (addrs []IP, err error) {
|
var lookupIP = oldLookupIP
|
||||||
|
|
||||||
|
func oldLookupIP(name string) (addrs []IP, err error) {
|
||||||
hostentLock.Lock()
|
hostentLock.Lock()
|
||||||
defer hostentLock.Unlock()
|
defer hostentLock.Unlock()
|
||||||
h, err := syscall.GetHostByName(name)
|
h, err := syscall.GetHostByName(name)
|
||||||
@ -56,7 +58,36 @@ func lookupIP(name string) (addrs []IP, err error) {
|
|||||||
}
|
}
|
||||||
addrs = addrs[0:i]
|
addrs = addrs[0:i]
|
||||||
default: // TODO(vcc): Implement non IPv4 address lookups.
|
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
|
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 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 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 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 GetIfEntry(pIfRow *MibIfRow) (errcode error) = iphlpapi.GetIfEntry
|
||||||
//sys GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) = iphlpapi.GetAdaptersInfo
|
//sys GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) = iphlpapi.GetAdaptersInfo
|
||||||
|
|
||||||
@ -522,6 +524,14 @@ type RawSockaddrInet4 struct {
|
|||||||
Zero [8]uint8
|
Zero [8]uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RawSockaddrInet6 struct {
|
||||||
|
Family uint16
|
||||||
|
Port uint16
|
||||||
|
Flowinfo uint32
|
||||||
|
Addr [16]byte /* in6_addr */
|
||||||
|
Scope_id uint32
|
||||||
|
}
|
||||||
|
|
||||||
type RawSockaddr struct {
|
type RawSockaddr struct {
|
||||||
Family uint16
|
Family uint16
|
||||||
Data [14]int8
|
Data [14]int8
|
||||||
@ -560,11 +570,22 @@ type SockaddrInet6 struct {
|
|||||||
Port int
|
Port int
|
||||||
ZoneId uint32
|
ZoneId uint32
|
||||||
Addr [16]byte
|
Addr [16]byte
|
||||||
|
raw RawSockaddrInet6
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sa *SockaddrInet6) sockaddr() (uintptr, int32, error) {
|
func (sa *SockaddrInet6) sockaddr() (uintptr, int32, error) {
|
||||||
// TODO(brainman): implement SockaddrInet6.sockaddr()
|
if sa.Port < 0 || sa.Port > 0xFFFF {
|
||||||
return 0, 0, EWINDOWS
|
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 {
|
type SockaddrUnix struct {
|
||||||
@ -592,7 +613,15 @@ func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) {
|
|||||||
return sa, nil
|
return sa, nil
|
||||||
|
|
||||||
case AF_INET6:
|
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
|
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)
|
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.
|
// Invented structures to support what package os expects.
|
||||||
type Rusage struct {
|
type Rusage struct {
|
||||||
CreationTime Filetime
|
CreationTime Filetime
|
||||||
|
@ -132,6 +132,8 @@ var (
|
|||||||
procgetprotobyname = modws2_32.NewProc("getprotobyname")
|
procgetprotobyname = modws2_32.NewProc("getprotobyname")
|
||||||
procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W")
|
procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W")
|
||||||
procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree")
|
procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree")
|
||||||
|
procGetAddrInfoW = modws2_32.NewProc("GetAddrInfoW")
|
||||||
|
procFreeAddrInfoW = modws2_32.NewProc("FreeAddrInfoW")
|
||||||
procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
|
procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
|
||||||
procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
|
procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
|
||||||
procTranslateNameW = modsecur32.NewProc("TranslateNameW")
|
procTranslateNameW = modsecur32.NewProc("TranslateNameW")
|
||||||
@ -1537,6 +1539,19 @@ func DnsRecordListFree(rl *DNSRecord, freetype uint32) {
|
|||||||
return
|
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) {
|
func GetIfEntry(pIfRow *MibIfRow) (errcode error) {
|
||||||
r0, _, _ := Syscall(procGetIfEntry.Addr(), 1, uintptr(unsafe.Pointer(pIfRow)), 0, 0)
|
r0, _, _ := Syscall(procGetIfEntry.Addr(), 1, uintptr(unsafe.Pointer(pIfRow)), 0, 0)
|
||||||
if r0 != 0 {
|
if r0 != 0 {
|
||||||
|
@ -132,6 +132,8 @@ var (
|
|||||||
procgetprotobyname = modws2_32.NewProc("getprotobyname")
|
procgetprotobyname = modws2_32.NewProc("getprotobyname")
|
||||||
procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W")
|
procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W")
|
||||||
procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree")
|
procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree")
|
||||||
|
procGetAddrInfoW = modws2_32.NewProc("GetAddrInfoW")
|
||||||
|
procFreeAddrInfoW = modws2_32.NewProc("FreeAddrInfoW")
|
||||||
procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
|
procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
|
||||||
procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
|
procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
|
||||||
procTranslateNameW = modsecur32.NewProc("TranslateNameW")
|
procTranslateNameW = modsecur32.NewProc("TranslateNameW")
|
||||||
@ -1537,6 +1539,19 @@ func DnsRecordListFree(rl *DNSRecord, freetype uint32) {
|
|||||||
return
|
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) {
|
func GetIfEntry(pIfRow *MibIfRow) (errcode error) {
|
||||||
r0, _, _ := Syscall(procGetIfEntry.Addr(), 1, uintptr(unsafe.Pointer(pIfRow)), 0, 0)
|
r0, _, _ := Syscall(procGetIfEntry.Addr(), 1, uintptr(unsafe.Pointer(pIfRow)), 0, 0)
|
||||||
if r0 != 0 {
|
if r0 != 0 {
|
||||||
|
@ -924,3 +924,20 @@ const (
|
|||||||
REG_DWORD = REG_DWORD_LITTLE_ENDIAN
|
REG_DWORD = REG_DWORD_LITTLE_ENDIAN
|
||||||
REG_QWORD = REG_QWORD_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