Commit 6c89f961 authored by Mikio Hara's avatar Mikio Hara

internal/netreflect: new package

This change introduces an internal package that provides the
manipulation of net package facilities by using runtime reflection.
The package is supposed to be used by ipv4 and ipv6 packages.

Change-Id: I73ec3b7d3762e675ca03ad9ee5e8a68e75ceb997
Reviewed-on: https://go-review.googlesource.com/27732
Run-TryBot: Mikio Hara <mikioh.mikioh@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
parent 3a1f9ef9
// Copyright 2016 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 netreflect implements run-time reflection for the
// facilities of net package.
package netreflect
import (
"errors"
"net"
)
var (
errInvalidType = errors.New("invalid type")
errOpNoSupport = errors.New("operation not supported")
)
// SocketOf returns the socket descriptor of c.
func SocketOf(c net.Conn) (uintptr, error) {
switch c.(type) {
case *net.TCPConn, *net.UDPConn, *net.IPConn, *net.UnixConn:
return socketOf(c)
default:
return 0, errInvalidType
}
}
// PacketSocketOf returns the socket descriptor of c.
func PacketSocketOf(c net.PacketConn) (uintptr, error) {
switch c.(type) {
case *net.UDPConn, *net.IPConn, *net.UnixConn:
return socketOf(c.(net.Conn))
default:
return 0, errInvalidType
}
}
// Copyright 2016 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.
// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
package netreflect
import (
"net"
"reflect"
"runtime"
)
func socketOf(c net.Conn) (uintptr, error) {
v := reflect.ValueOf(c)
switch e := v.Elem(); e.Kind() {
case reflect.Struct:
fd := e.FieldByName("conn").FieldByName("fd")
switch e := fd.Elem(); e.Kind() {
case reflect.Struct:
sysfd := e.FieldByName("sysfd")
if runtime.GOOS == "windows" {
return uintptr(sysfd.Uint()), nil
}
return uintptr(sysfd.Int()), nil
}
}
return 0, errInvalidType
}
// Copyright 2016 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.
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
package netreflect
import "net"
func socketOf(c net.Conn) (uintptr, error) { return 0, errOpNoSupport }
// Copyright 2016 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 netreflect_test
import (
"fmt"
"io/ioutil"
"net"
"os"
"runtime"
"testing"
"golang.org/x/net/internal/netreflect"
)
func localPath() string {
f, err := ioutil.TempFile("", "netreflect")
if err != nil {
panic(err)
}
path := f.Name()
f.Close()
os.Remove(path)
return path
}
func newLocalListener(network string) (net.Listener, error) {
switch network {
case "tcp":
if ln, err := net.Listen("tcp4", "127.0.0.1:0"); err == nil {
return ln, nil
}
return net.Listen("tcp6", "[::1]:0")
case "tcp4":
return net.Listen("tcp4", "127.0.0.1:0")
case "tcp6":
return net.Listen("tcp6", "[::1]:0")
case "unix", "unixpacket":
return net.Listen(network, localPath())
}
return nil, fmt.Errorf("%s is not supported", network)
}
func newLocalPacketListener(network string) (net.PacketConn, error) {
switch network {
case "udp":
if c, err := net.ListenPacket("udp4", "127.0.0.1:0"); err == nil {
return c, nil
}
return net.ListenPacket("udp6", "[::1]:0")
case "udp4":
return net.ListenPacket("udp4", "127.0.0.1:0")
case "udp6":
return net.ListenPacket("udp6", "[::1]:0")
case "unixgram":
return net.ListenPacket(network, localPath())
}
return nil, fmt.Errorf("%s is not supported", network)
}
func TestSocketOf(t *testing.T) {
for _, network := range []string{"tcp", "unix", "unixpacket"} {
switch network {
case "unix":
switch runtime.GOOS {
case "nacl", "plan9", "windows":
continue
}
case "unixpacket":
switch runtime.GOOS {
case "darwin", "nacl", "plan9", "windows":
continue
}
}
ln, err := newLocalListener(network)
if err != nil {
t.Error(err)
continue
}
defer func() {
path := ln.Addr().String()
ln.Close()
if network == "unix" || network == "unixpacket" {
os.Remove(path)
}
}()
c, err := net.Dial(ln.Addr().Network(), ln.Addr().String())
if err != nil {
t.Error(err)
continue
}
defer c.Close()
if _, err := netreflect.SocketOf(c); err != nil {
t.Error(err)
continue
}
}
}
func TestPacketSocketOf(t *testing.T) {
for _, network := range []string{"udp", "unixgram"} {
switch network {
case "unixgram":
switch runtime.GOOS {
case "nacl", "plan9", "windows":
continue
}
}
c, err := newLocalPacketListener(network)
if err != nil {
t.Error(err)
continue
}
defer c.Close()
if _, err := netreflect.PacketSocketOf(c); err != nil {
t.Error(err)
continue
}
}
}
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