diff options
Diffstat (limited to 'src/net/rawconn_windows_test.go')
-rw-r--r-- | src/net/rawconn_windows_test.go | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/src/net/rawconn_windows_test.go b/src/net/rawconn_windows_test.go new file mode 100644 index 0000000..5febf08 --- /dev/null +++ b/src/net/rawconn_windows_test.go @@ -0,0 +1,116 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "errors" + "syscall" + "unsafe" +) + +func readRawConn(c syscall.RawConn, b []byte) (int, error) { + var operr error + var n int + err := c.Read(func(s uintptr) bool { + var read uint32 + var flags uint32 + var buf syscall.WSABuf + buf.Buf = &b[0] + buf.Len = uint32(len(b)) + operr = syscall.WSARecv(syscall.Handle(s), &buf, 1, &read, &flags, nil, nil) + n = int(read) + return true + }) + if err != nil { + return n, err + } + return n, operr +} + +func writeRawConn(c syscall.RawConn, b []byte) error { + var operr error + err := c.Write(func(s uintptr) bool { + var written uint32 + var buf syscall.WSABuf + buf.Buf = &b[0] + buf.Len = uint32(len(b)) + operr = syscall.WSASend(syscall.Handle(s), &buf, 1, &written, 0, nil, nil) + return true + }) + if err != nil { + return err + } + return operr +} + +func controlRawConn(c syscall.RawConn, addr Addr) error { + var operr error + fn := func(s uintptr) { + var v, l int32 + l = int32(unsafe.Sizeof(v)) + operr = syscall.Getsockopt(syscall.Handle(s), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, (*byte)(unsafe.Pointer(&v)), &l) + if operr != nil { + return + } + switch addr := addr.(type) { + case *TCPAddr: + // There's no guarantee that IP-level socket + // options work well with dual stack sockets. + // A simple solution would be to take a look + // at the bound address to the raw connection + // and to classify the address family of the + // underlying socket by the bound address: + // + // - When IP.To16() != nil and IP.To4() == nil, + // we can assume that the raw connection + // consists of an IPv6 socket using only + // IPv6 addresses. + // + // - When IP.To16() == nil and IP.To4() != nil, + // the raw connection consists of an IPv4 + // socket using only IPv4 addresses. + // + // - Otherwise, the raw connection is a dual + // stack socket, an IPv6 socket using IPv6 + // addresses including IPv4-mapped or + // IPv4-embedded IPv6 addresses. + if addr.IP.To16() != nil && addr.IP.To4() == nil { + operr = syscall.SetsockoptInt(syscall.Handle(s), syscall.IPPROTO_IPV6, syscall.IPV6_UNICAST_HOPS, 1) + } else if addr.IP.To16() == nil && addr.IP.To4() != nil { + operr = syscall.SetsockoptInt(syscall.Handle(s), syscall.IPPROTO_IP, syscall.IP_TTL, 1) + } + } + } + if err := c.Control(fn); err != nil { + return err + } + return operr +} + +func controlOnConnSetup(network string, address string, c syscall.RawConn) error { + var operr error + var fn func(uintptr) + switch network { + case "tcp", "udp", "ip": + return errors.New("ambiguous network: " + network) + default: + switch network[len(network)-1] { + case '4': + fn = func(s uintptr) { + operr = syscall.SetsockoptInt(syscall.Handle(s), syscall.IPPROTO_IP, syscall.IP_TTL, 1) + } + case '6': + fn = func(s uintptr) { + operr = syscall.SetsockoptInt(syscall.Handle(s), syscall.IPPROTO_IPV6, syscall.IPV6_UNICAST_HOPS, 1) + } + default: + return errors.New("unknown network: " + network) + } + } + if err := c.Control(fn); err != nil { + return err + } + return operr +} |