]> Cypherpunks repositories - gostls13.git/commitdiff
net: protocol specific listen functions return a proper local socket address
authorMikio Hara <mikioh.mikioh@gmail.com>
Tue, 13 Nov 2012 03:56:28 +0000 (12:56 +0900)
committerMikio Hara <mikioh.mikioh@gmail.com>
Tue, 13 Nov 2012 03:56:28 +0000 (12:56 +0900)
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

src/pkg/net/ipraw_test.go
src/pkg/net/iprawsock_posix.go
src/pkg/net/tcp_test.go
src/pkg/net/tcpsock_plan9.go
src/pkg/net/tcpsock_posix.go
src/pkg/net/udp_test.go
src/pkg/net/udpsock_plan9.go
src/pkg/net/udpsock_posix.go

index 29d5984bdfe4dc47e0e99c488c8262eacd21d8c0..43b02aef2ea1f040a9292b769857222ce4d4e955 100644 (file)
@@ -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
+               }
+       }
+}
index 4d8b5341d97c82bceb95ad04a22adbca70ebbeb1..00e87cfbf0dda38c65d9d314f56f924a0c5eaf58 100644 (file)
@@ -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 {
index 53daf5b0999cffde8197ba8c948d1445ad907af0..f6e4df30a8b322f50d254b0c46ad95d91e7a78ac 100644 (file)
@@ -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
+               }
+       }
+}
index a77633b355e495a25f556adf3c184da338fd990b..d4d39e80f4acde4f044a1f0095da71df08b2026f 100644 (file)
@@ -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 {
index 09654a4b580cbb36ceaa9cc4c972f897d90eeb39..7b827f1e97133d6d4b17702d170e0e9cd328d727 100644 (file)
@@ -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) {
-       return dialTCP(net, laddr, raddr, noDeadline)
-}
-
-func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*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) {
        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
+}
index f80d3b5a9cfa77e2e50549406e13a42e24b60155..37b904f3242218d606b7ea1a2a1ab0f43a34f00b 100644 (file)
@@ -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
+               }
+       }
+}
index c04660baa27536a8fcd4df814b39d61347953654..767a421cba4447aeb9fc633c3dadad0463e6b00c 100644 (file)
@@ -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 {
index f6e2c17c3cb9543b816a1190befa239f3e882fb3..d7329bf32fc1809fce396a925b3ef7a3dd681be9 100644 (file)
@@ -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 {