1
0
mirror of https://github.com/golang/go synced 2024-11-20 08:54:40 -07:00

net: fix spurious EADDRNOTAVAIL errors

R=golang-dev, fullung
CC=golang-dev
https://golang.org/cl/6443085
This commit is contained in:
Russ Cox 2012-08-06 16:32:00 -04:00
parent 8b5d4c3c03
commit e1cf7d6fb6

View 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.