mirror of
https://github.com/golang/go
synced 2024-11-20 08:04:42 -07:00
net: protocol specific listen functions return a proper local socket address
When a nil listener address is passed to some protocol specific listen function, it will create an unnamed, unbound socket because of the nil listener address. Other listener functions may return invalid address error. This CL allows to pass a nil listener address to all protocol specific listen functions to fix above inconsistency. Also make it possible to return a proper local socket address in case of a nil listner address. Fixes #4190. Fixes #3847. R=rsc, iant CC=golang-dev https://golang.org/cl/6525048
This commit is contained in:
parent
0ae80785e6
commit
677c6e6ee7
@ -206,3 +206,33 @@ func parseICMPEchoReply(b []byte) (id, seqnum int) {
|
||||
seqnum = int(b[6])<<8 | int(b[7])
|
||||
return
|
||||
}
|
||||
|
||||
var ipConnLocalNameTests = []struct {
|
||||
net string
|
||||
laddr *IPAddr
|
||||
}{
|
||||
{"ip4:icmp", &IPAddr{IP: IPv4(127, 0, 0, 1)}},
|
||||
{"ip4:icmp", &IPAddr{}},
|
||||
{"ip4:icmp", nil},
|
||||
}
|
||||
|
||||
func TestIPConnLocalName(t *testing.T) {
|
||||
if os.Getuid() != 0 {
|
||||
t.Logf("skipping test; must be root")
|
||||
return
|
||||
}
|
||||
|
||||
for _, tt := range ipConnLocalNameTests {
|
||||
c, err := ListenIP(tt.net, tt.laddr)
|
||||
if err != nil {
|
||||
t.Errorf("ListenIP failed: %v", err)
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
la := c.LocalAddr()
|
||||
if la == nil {
|
||||
t.Error("IPConn.LocalAddr failed")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn,
|
||||
switch net {
|
||||
case "ip", "ip4", "ip6":
|
||||
default:
|
||||
return nil, UnknownNetworkError(net)
|
||||
return nil, UnknownNetworkError(netProto)
|
||||
}
|
||||
if raddr == nil {
|
||||
return nil, &OpError{"dial", netProto, nil, errMissingAddress}
|
||||
@ -199,7 +199,7 @@ func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
|
||||
switch net {
|
||||
case "ip", "ip4", "ip6":
|
||||
default:
|
||||
return nil, UnknownNetworkError(net)
|
||||
return nil, UnknownNetworkError(netProto)
|
||||
}
|
||||
fd, err := internetSocket(net, laddr.toAddr(), nil, noDeadline, syscall.SOCK_RAW, proto, "listen", sockaddrToIP)
|
||||
if err != nil {
|
||||
|
@ -116,3 +116,33 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool) {
|
||||
sem <- true
|
||||
}
|
||||
}
|
||||
|
||||
var tcpListenerNameTests = []struct {
|
||||
net string
|
||||
laddr *TCPAddr
|
||||
}{
|
||||
{"tcp4", &TCPAddr{IP: IPv4(127, 0, 0, 1)}},
|
||||
{"tcp4", &TCPAddr{}},
|
||||
{"tcp4", nil},
|
||||
}
|
||||
|
||||
func TestTCPListenerName(t *testing.T) {
|
||||
if testing.Short() || !*testExternal {
|
||||
t.Logf("skipping test to avoid external network")
|
||||
return
|
||||
}
|
||||
|
||||
for _, tt := range tcpListenerNameTests {
|
||||
ln, err := ListenTCP(tt.net, tt.laddr)
|
||||
if err != nil {
|
||||
t.Errorf("ListenTCP failed: %v", err)
|
||||
return
|
||||
}
|
||||
defer ln.Close()
|
||||
la := ln.Addr()
|
||||
if a, ok := la.(*TCPAddr); !ok || a.Port == 0 {
|
||||
t.Errorf("got %v; expected a proper address with non-zero port number", la)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err error) {
|
||||
return nil, UnknownNetworkError(net)
|
||||
}
|
||||
if laddr == nil {
|
||||
return nil, &OpError{"listen", net, nil, errMissingAddress}
|
||||
laddr = &TCPAddr{}
|
||||
}
|
||||
l1, err := listenPlan9(net, laddr)
|
||||
if err != nil {
|
||||
|
@ -143,14 +143,18 @@ func (c *TCPConn) SetNoDelay(noDelay bool) error {
|
||||
// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used
|
||||
// as the local address for the connection.
|
||||
func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
|
||||
switch net {
|
||||
case "tcp", "tcp4", "tcp6":
|
||||
default:
|
||||
return nil, UnknownNetworkError(net)
|
||||
}
|
||||
if raddr == nil {
|
||||
return nil, &OpError{"dial", net, nil, errMissingAddress}
|
||||
}
|
||||
return dialTCP(net, laddr, raddr, noDeadline)
|
||||
}
|
||||
|
||||
func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, error) {
|
||||
if raddr == nil {
|
||||
return nil, &OpError{"dial", net, nil, errMissingAddress}
|
||||
}
|
||||
|
||||
fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), deadline, syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
|
||||
|
||||
// TCP has a rarely used mechanism called a 'simultaneous connection' in
|
||||
@ -224,25 +228,6 @@ type TCPListener struct {
|
||||
fd *netFD
|
||||
}
|
||||
|
||||
// ListenTCP announces on the TCP address laddr and returns a TCP listener.
|
||||
// Net must be "tcp", "tcp4", or "tcp6".
|
||||
// If laddr has a port of 0, it means to listen on some available port.
|
||||
// The caller can use l.Addr() to retrieve the chosen address.
|
||||
func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
|
||||
fd, err := internetSocket(net, laddr.toAddr(), nil, noDeadline, syscall.SOCK_STREAM, 0, "listen", sockaddrToTCP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = syscall.Listen(fd.sysfd, listenerBacklog)
|
||||
if err != nil {
|
||||
closesocket(fd.sysfd)
|
||||
return nil, &OpError{"listen", net, laddr, err}
|
||||
}
|
||||
l := new(TCPListener)
|
||||
l.fd = fd
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// AcceptTCP accepts the next incoming call and returns the new connection
|
||||
// and the remote address.
|
||||
func (l *TCPListener) AcceptTCP() (c *TCPConn, err error) {
|
||||
@ -291,3 +276,30 @@ func (l *TCPListener) SetDeadline(t time.Time) error {
|
||||
// It is the caller's responsibility to close f when finished.
|
||||
// Closing l does not affect f, and closing f does not affect l.
|
||||
func (l *TCPListener) File() (f *os.File, err error) { return l.fd.dup() }
|
||||
|
||||
// ListenTCP announces on the TCP address laddr and returns a TCP listener.
|
||||
// Net must be "tcp", "tcp4", or "tcp6".
|
||||
// If laddr has a port of 0, it means to listen on some available port.
|
||||
// The caller can use l.Addr() to retrieve the chosen address.
|
||||
func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
|
||||
switch net {
|
||||
case "tcp", "tcp4", "tcp6":
|
||||
default:
|
||||
return nil, UnknownNetworkError(net)
|
||||
}
|
||||
if laddr == nil {
|
||||
laddr = &TCPAddr{}
|
||||
}
|
||||
fd, err := internetSocket(net, laddr.toAddr(), nil, noDeadline, syscall.SOCK_STREAM, 0, "listen", sockaddrToTCP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = syscall.Listen(fd.sysfd, listenerBacklog)
|
||||
if err != nil {
|
||||
closesocket(fd.sysfd)
|
||||
return nil, &OpError{"listen", net, laddr, err}
|
||||
}
|
||||
l := new(TCPListener)
|
||||
l.fd = fd
|
||||
return l, nil
|
||||
}
|
||||
|
@ -87,3 +87,33 @@ func testWriteToPacketConn(t *testing.T, raddr string) {
|
||||
t.Fatal("Write should fail")
|
||||
}
|
||||
}
|
||||
|
||||
var udpConnLocalNameTests = []struct {
|
||||
net string
|
||||
laddr *UDPAddr
|
||||
}{
|
||||
{"udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)}},
|
||||
{"udp4", &UDPAddr{}},
|
||||
{"udp4", nil},
|
||||
}
|
||||
|
||||
func TestUDPConnLocalName(t *testing.T) {
|
||||
if testing.Short() || !*testExternal {
|
||||
t.Logf("skipping test to avoid external network")
|
||||
return
|
||||
}
|
||||
|
||||
for _, tt := range udpConnLocalNameTests {
|
||||
c, err := ListenUDP(tt.net, tt.laddr)
|
||||
if err != nil {
|
||||
t.Errorf("ListenUDP failed: %v", err)
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
la := c.LocalAddr()
|
||||
if a, ok := la.(*UDPAddr); !ok || a.Port == 0 {
|
||||
t.Errorf("got %v; expected a proper address with non-zero port number", la)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ func ListenUDP(net string, laddr *UDPAddr) (c *UDPConn, err error) {
|
||||
return nil, UnknownNetworkError(net)
|
||||
}
|
||||
if laddr == nil {
|
||||
return nil, &OpError{"listen", net, nil, errMissingAddress}
|
||||
laddr = &UDPAddr{}
|
||||
}
|
||||
l, err := listenPlan9(net, laddr)
|
||||
if err != nil {
|
||||
|
@ -193,7 +193,7 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
|
||||
return nil, UnknownNetworkError(net)
|
||||
}
|
||||
if laddr == nil {
|
||||
return nil, &OpError{"listen", net, nil, errMissingAddress}
|
||||
laddr = &UDPAddr{}
|
||||
}
|
||||
fd, err := internetSocket(net, laddr.toAddr(), nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user