]> Cypherpunks repositories - gostls13.git/commitdiff
net: fix spurious EADDRNOTAVAIL errors
authorRuss Cox <rsc@golang.org>
Mon, 6 Aug 2012 20:32:00 +0000 (16:32 -0400)
committerRuss Cox <rsc@golang.org>
Mon, 6 Aug 2012 20:32:00 +0000 (16:32 -0400)
R=golang-dev, fullung
CC=golang-dev
https://golang.org/cl/6443085

src/pkg/net/tcpsock_posix.go

index b96531694e6711517f0026772c11ab6de69c0a1a..2c34d2fda7d847e65554c040aa6ccbef7455b93a 100644 (file)
@@ -166,8 +166,17 @@ func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
        // use the result.  See also:
        //      http://golang.org/issue/2690
        //      http://stackoverflow.com/questions/4949858/
-       for i := 0; i < 2 && err == nil && laddr == nil && selfConnect(fd); i++ {
-               fd.Close()
+       //
+       // The opposite can also happen: if we ask the kernel to pick an appropriate
+       // originating local address, sometimes it picks one that is already in use.
+       // So if the error is EADDRNOTAVAIL, we have to try again too, just for
+       // a different reason.
+       //
+       // The kernel socket code is no doubt enjoying watching us squirm.
+       for i := 0; i < 2 && (laddr == nil || laddr.Port == 0) && (selfConnect(fd, err) || spuriousENOTAVAIL(err)); i++ {
+               if err == nil {
+                       fd.Close()
+               }
                fd, err = internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
        }
 
@@ -177,7 +186,12 @@ func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
        return newTCPConn(fd), nil
 }
 
-func selfConnect(fd *netFD) bool {
+func selfConnect(fd *netFD, err error) bool {
+       // If the connect failed, we clearly didn't connect to ourselves.
+       if err != nil {
+               return false
+       }
+
        // The socket constructor can return an fd with raddr nil under certain
        // unknown conditions. The errors in the calls there to Getpeername
        // are discarded, but we can't catch the problem there because those
@@ -194,6 +208,11 @@ func selfConnect(fd *netFD) bool {
        return l.Port == r.Port && l.IP.Equal(r.IP)
 }
 
+func spuriousENOTAVAIL(err error) bool {
+       e, ok := err.(*OpError)
+       return ok && e.Err == syscall.EADDRNOTAVAIL
+}
+
 // TCPListener is a TCP network listener.
 // Clients should typically use variables of type Listener
 // instead of assuming TCP.