Skip to content

Commit

Permalink
ipv6: implement control messages on windows
Browse files Browse the repository at this point in the history
Fixes golang/go#7174

Change-Id: I49dc79f4a2ad1889287f77109db7bdc7d0e6db1f
  • Loading branch information
tmm1 committed Nov 8, 2017
1 parent 81dab16 commit e5e9bea
Show file tree
Hide file tree
Showing 13 changed files with 69 additions and 37 deletions.
2 changes: 1 addition & 1 deletion ipv6/control_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin dragonfly freebsd linux netbsd openbsd solaris
// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows

package ipv6

Expand Down
16 changes: 0 additions & 16 deletions ipv6/control_windows.go

This file was deleted.

4 changes: 2 additions & 2 deletions ipv6/multicast_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ var packetConnReadWriteMulticastUDPTests = []struct {

func TestPacketConnReadWriteMulticastUDP(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
Expand Down Expand Up @@ -129,7 +129,7 @@ var packetConnReadWriteMulticastICMPTests = []struct {

func TestPacketConnReadWriteMulticastICMP(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
Expand Down
14 changes: 9 additions & 5 deletions ipv6/multicastlistener_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ var udpMultipleGroupListenerTests = []net.Addr{

func TestUDPSinglePacketConnWithMultipleGroupListeners(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
Expand Down Expand Up @@ -61,7 +61,7 @@ func TestUDPSinglePacketConnWithMultipleGroupListeners(t *testing.T) {

func TestUDPMultiplePacketConnWithMultipleGroupListeners(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
Expand Down Expand Up @@ -116,8 +116,10 @@ func TestUDPMultiplePacketConnWithMultipleGroupListeners(t *testing.T) {

func TestUDPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
case "windows":
t.Skipf("binding by interface name not supported on windows")
}
if !supportsIPv6 {
t.Skip("ipv6 is not supported")
Expand Down Expand Up @@ -172,7 +174,7 @@ func TestUDPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) {

func TestIPSinglePacketConnWithSingleGroupListener(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
Expand Down Expand Up @@ -216,7 +218,9 @@ func TestIPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) {
switch runtime.GOOS {
case "darwin", "dragonfly", "openbsd": // platforms that return fe80::1%lo0: bind: can't assign requested address
t.Skipf("not supported on %s", runtime.GOOS)
case "nacl", "plan9", "windows":
case "windows":
t.Skipf("binding by interface name not supported on windows")
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
Expand Down
3 changes: 0 additions & 3 deletions ipv6/payload.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ import (
"golang.org/x/net/internal/socket"
)

// BUG(mikio): On Windows, the ControlMessage for ReadFrom and WriteTo
// methods of PacketConn is not implemented.

// A payloadHandler represents the IPv6 datagram payload handler.
type payloadHandler struct {
net.PacketConn
Expand Down
2 changes: 1 addition & 1 deletion ipv6/payload_cmsg.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build !nacl,!plan9,!windows
// +build !nacl,!plan9

package ipv6

Expand Down
2 changes: 1 addition & 1 deletion ipv6/payload_cmsg_go1_9.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.

// +build go1.9
// +build !nacl,!plan9,!windows
// +build !nacl,!plan9

package ipv6

Expand Down
2 changes: 1 addition & 1 deletion ipv6/payload_nocmsg.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build nacl plan9 windows
// +build nacl plan9

package ipv6

Expand Down
6 changes: 4 additions & 2 deletions ipv6/readwrite_go1_9_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (

func BenchmarkPacketConnReadWriteUnicast(b *testing.B) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "nacl", "plan9":
b.Skipf("not supported on %s", runtime.GOOS)
}

Expand Down Expand Up @@ -169,7 +169,9 @@ func BenchmarkPacketConnReadWriteUnicast(b *testing.B) {

func TestPacketConnConcurrentReadWriteUnicast(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "windows":
t.Skipf("test hangs on windows")
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}

Expand Down
4 changes: 3 additions & 1 deletion ipv6/readwrite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ func BenchmarkReadWriteUnicast(b *testing.B) {

func TestPacketConnConcurrentReadWriteUnicastUDP(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "windows":
t.Skipf("test hangs on windows")
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
Expand Down
40 changes: 39 additions & 1 deletion ipv6/sys_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package ipv6
import (
"net"
"syscall"
"unsafe"

"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
Expand All @@ -23,6 +24,7 @@ const (
sysIPV6_PKTINFO = 0x13

sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14

sizeofIPv6Mreq = 0x14
sizeofIPv6Mtuinfo = 0x20
Expand All @@ -37,6 +39,11 @@ type sockaddrInet6 struct {
Scope_id uint32
}

type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}

type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
Expand All @@ -52,7 +59,9 @@ type icmpv6Filter struct {
}

var (
ctlOpts = [ctlMax]ctlOpt{}
ctlOpts = [ctlMax]ctlOpt{
ctlPacketInfo: {sysIPV6_PKTINFO, sizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo},
}

sockOpts = map[int]*sockOpt{
ssoHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_UNICAST_HOPS, Len: 4}},
Expand All @@ -61,6 +70,7 @@ var (
ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_LOOP, Len: 4}},
ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_JOIN_GROUP, Len: sizeofIPv6Mreq}, typ: ssoTypeIPMreq},
ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_LEAVE_GROUP, Len: sizeofIPv6Mreq}, typ: ssoTypeIPMreq},
ssoReceivePacketInfo: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_PKTINFO, Len: 4}},
}
)

Expand All @@ -70,6 +80,34 @@ func (sa *sockaddrInet6) setSockaddr(ip net.IP, i int) {
sa.Scope_id = uint32(i)
}

func (pi *inet6Pktinfo) setIfindex(i int) {
pi.Ifindex = int32(i)
}

func (mreq *ipv6Mreq) setIfindex(i int) {
mreq.Interface = uint32(i)
}

func marshalPacketInfo(b []byte, cm *ControlMessage) []byte {
m := socket.ControlMessage(b)
m.MarshalHeader(iana.ProtocolIP, sysIPV6_PKTINFO, sizeofInet6Pktinfo)
if cm != nil {
pi := (*inet6Pktinfo)(unsafe.Pointer(&m.Data(sizeofInet6Pktinfo)[0]))
if ip := cm.Src.To16(); ip != nil {
copy(pi.Addr[:], ip)
}
if cm.IfIndex > 0 {
pi.setIfindex(cm.IfIndex)
}
}
return m.Next(sizeofInet6Pktinfo)
}

func parsePacketInfo(cm *ControlMessage, b []byte) {
pi := (*inet6Pktinfo)(unsafe.Pointer(&b[0]))
cm.IfIndex = int(pi.Ifindex)
if len(cm.Dst) < net.IPv6len {
cm.Dst = make(net.IP, net.IPv6len)
}
copy(cm.Dst, pi.Addr[:])
}
4 changes: 3 additions & 1 deletion ipv6/unicast_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ import (

func TestPacketConnReadWriteUnicastUDP(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "windows":
t.Skipf("fails in sendmsg with invalid argument")
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
Expand Down
7 changes: 5 additions & 2 deletions ipv6/unicastsockopt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (

func TestConnUnicastSocketOptions(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
Expand Down Expand Up @@ -61,7 +61,7 @@ var packetConnUnicastSocketOptionTests = []struct {

func TestPacketConnUnicastSocketOptions(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv6 {
Expand Down Expand Up @@ -95,6 +95,9 @@ func testUnicastSocketOptions(t *testing.T, c testIPv6UnicastConn) {
tclass := iana.DiffServCS0 | iana.NotECNTransport
if err := c.SetTrafficClass(tclass); err != nil {
switch runtime.GOOS {
case "windows":
// no IPV6_TCLASS on Windows, must use qWAVE
t.Skipf("not supported on %s", runtime.GOOS)
case "darwin": // older darwin kernels don't support IPV6_TCLASS option
t.Logf("not supported on %s", runtime.GOOS)
goto next
Expand Down

0 comments on commit e5e9bea

Please sign in to comment.