mirror of
https://github.com/golang/go.git
synced 2025-05-30 11:51:34 +00:00
net: make {TCP,Unix}Listener implement syscall.Conn
This change adds the syscall.Conn interface to Listener types, with the caveat that only RawConn.Control is supported. Custom socket options can now be set safely. Updates #19435 Fixes #22065 Change-Id: I7e74780d00318dc54a923d1c628a18a36009acab Reviewed-on: https://go-review.googlesource.com/71651 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
ff4ee88162
commit
eed308de31
@ -60,3 +60,19 @@ func (c *rawConn) Write(f func(uintptr) bool) error {
|
|||||||
func newRawConn(fd *netFD) (*rawConn, error) {
|
func newRawConn(fd *netFD) (*rawConn, error) {
|
||||||
return &rawConn{fd: fd}, nil
|
return &rawConn{fd: fd}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type rawListener struct {
|
||||||
|
rawConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *rawListener) Read(func(uintptr) bool) error {
|
||||||
|
return syscall.EINVAL
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *rawListener) Write(func(uintptr) bool) error {
|
||||||
|
return syscall.EINVAL
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRawListener(fd *netFD) (*rawListener, error) {
|
||||||
|
return &rawListener{rawConn{fd: fd}}, nil
|
||||||
|
}
|
||||||
|
@ -92,3 +92,53 @@ func TestRawConn(t *testing.T) {
|
|||||||
t.Fatal("should fail")
|
t.Fatal("should fail")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRawConnListener(t *testing.T) {
|
||||||
|
ln, err := newLocalListener("tcp")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer ln.Close()
|
||||||
|
|
||||||
|
cc, err := ln.(*TCPListener).SyscallConn()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
called := false
|
||||||
|
op := func(uintptr) bool {
|
||||||
|
called = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
err = cc.Write(op)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Write should return an error")
|
||||||
|
}
|
||||||
|
if called {
|
||||||
|
t.Error("Write shouldn't call op")
|
||||||
|
}
|
||||||
|
|
||||||
|
called = false
|
||||||
|
err = cc.Read(op)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Read should return an error")
|
||||||
|
}
|
||||||
|
if called {
|
||||||
|
t.Error("Read shouldn't call op")
|
||||||
|
}
|
||||||
|
|
||||||
|
var operr error
|
||||||
|
fn := func(s uintptr) {
|
||||||
|
_, operr = syscall.GetsockoptInt(int(s), syscall.SOL_SOCKET, syscall.SO_REUSEADDR)
|
||||||
|
}
|
||||||
|
err = cc.Control(fn)
|
||||||
|
if err != nil || operr != nil {
|
||||||
|
t.Fatal(err, operr)
|
||||||
|
}
|
||||||
|
ln.Close()
|
||||||
|
err = cc.Control(fn)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Control after Close should fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -7,6 +7,7 @@ package net
|
|||||||
import (
|
import (
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRawConn(t *testing.T) {
|
func TestRawConn(t *testing.T) {
|
||||||
@ -34,3 +35,55 @@ func TestRawConn(t *testing.T) {
|
|||||||
t.Fatal("should fail")
|
t.Fatal("should fail")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRawConnListener(t *testing.T) {
|
||||||
|
ln, err := newLocalListener("tcp")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer ln.Close()
|
||||||
|
|
||||||
|
cc, err := ln.(*TCPListener).SyscallConn()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
called := false
|
||||||
|
op := func(uintptr) bool {
|
||||||
|
called = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
err = cc.Write(op)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Write should return an error")
|
||||||
|
}
|
||||||
|
if called {
|
||||||
|
t.Error("Write shouldn't call op")
|
||||||
|
}
|
||||||
|
|
||||||
|
called = false
|
||||||
|
err = cc.Read(op)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Read should return an error")
|
||||||
|
}
|
||||||
|
if called {
|
||||||
|
t.Error("Read shouldn't call op")
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
err = cc.Control(fn)
|
||||||
|
if err != nil || operr != nil {
|
||||||
|
t.Fatal(err, operr)
|
||||||
|
}
|
||||||
|
ln.Close()
|
||||||
|
err = cc.Control(fn)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Control after Close should fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -225,6 +225,18 @@ type TCPListener struct {
|
|||||||
fd *netFD
|
fd *netFD
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SyscallConn returns a raw network connection.
|
||||||
|
// This implements the syscall.Conn interface.
|
||||||
|
//
|
||||||
|
// The returned RawConn only supports calling Control. Read and
|
||||||
|
// Write return an error.
|
||||||
|
func (l *TCPListener) SyscallConn() (syscall.RawConn, error) {
|
||||||
|
if !l.ok() {
|
||||||
|
return nil, syscall.EINVAL
|
||||||
|
}
|
||||||
|
return newRawListener(l.fd)
|
||||||
|
}
|
||||||
|
|
||||||
// AcceptTCP accepts the next incoming call and returns the new
|
// AcceptTCP accepts the next incoming call and returns the new
|
||||||
// connection.
|
// connection.
|
||||||
func (l *TCPListener) AcceptTCP() (*TCPConn, error) {
|
func (l *TCPListener) AcceptTCP() (*TCPConn, error) {
|
||||||
|
@ -219,6 +219,18 @@ type UnixListener struct {
|
|||||||
|
|
||||||
func (ln *UnixListener) ok() bool { return ln != nil && ln.fd != nil }
|
func (ln *UnixListener) ok() bool { return ln != nil && ln.fd != nil }
|
||||||
|
|
||||||
|
// SyscallConn returns a raw network connection.
|
||||||
|
// This implements the syscall.Conn interface.
|
||||||
|
//
|
||||||
|
// The returned RawConn only supports calling Control. Read and
|
||||||
|
// Write return an error.
|
||||||
|
func (l *UnixListener) SyscallConn() (syscall.RawConn, error) {
|
||||||
|
if !l.ok() {
|
||||||
|
return nil, syscall.EINVAL
|
||||||
|
}
|
||||||
|
return newRawListener(l.fd)
|
||||||
|
}
|
||||||
|
|
||||||
// AcceptUnix accepts the next incoming call and returns the new
|
// AcceptUnix accepts the next incoming call and returns the new
|
||||||
// connection.
|
// connection.
|
||||||
func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
|
func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user