diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 4a5412434..c7f985d88 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -160,7 +160,7 @@ }, { "ImportPath": "github.com/jbenet/go-reuseport", - "Rev": "f2ab96a83e1b33b66478eedd314884755d771933" + "Rev": "1e1968c4744fef51234e83f015aa0187b4bd796b" }, { "ImportPath": "github.com/jbenet/go-sockaddr/net", diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/impl_unix.go b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/impl_unix.go index bf94183e1..ed8415abd 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/impl_unix.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/impl_unix.go @@ -106,18 +106,27 @@ func dial(dialer net.Dialer, netw, addr string) (c net.Conn, err error) { } } - if fd, err = socket(rfamily, socktype, rprotocol); err != nil { - return nil, err - } + // look at dialTCP in http://golang.org/src/net/tcpsock_posix.go .... ! + // here we just try again 3 times. + for i := 0; i < 3; i++ { + if fd, err = socket(rfamily, socktype, rprotocol); err != nil { + return nil, err + } - if err = syscall.Bind(fd, localSockaddr); err != nil { - // fmt.Println("bind failed") - syscall.Close(fd) - return nil, err + if err = syscall.Bind(fd, localSockaddr); err != nil { + // fmt.Println("bind failed") + syscall.Close(fd) + return nil, err + } + if err = connect(fd, remoteSockaddr); err != nil { + syscall.Close(fd) + // fmt.Println("connect failed", localSockaddr, err) + continue // try again. + } + + break } - if err = connect(fd, remoteSockaddr); err != nil { - syscall.Close(fd) - // fmt.Println("connect failed", localSockaddr, err) + if err != nil { return nil, err } @@ -314,6 +323,7 @@ func connect(fd int, ra syscall.Sockaddr) error { } var err error + start := time.Now() for { // if err := fd.pd.WaitWrite(); err != nil { // return err @@ -321,7 +331,8 @@ func connect(fd int, ra syscall.Sockaddr) error { // i'd use the above fd.pd.WaitWrite to poll io correctly, just like net sockets... // but of course, it uses fucking runtime_* functions that _cannot_ be used by // non-go-stdlib source... seriously guys, what kind of bullshit is that!? - <-time.After(20 * time.Microsecond) + // we're relegated to using syscall.Select (what nightmare that is) or using + // a simple but totally bogus time-based wait. garbage. var nerr int nerr, err = syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_ERROR) if err != nil { @@ -329,6 +340,10 @@ func connect(fd int, ra syscall.Sockaddr) error { } switch err = syscall.Errno(nerr); err { case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR: + if time.Now().Sub(start) > time.Second { + return err + } + <-time.After(20 * time.Microsecond) case syscall.Errno(0), syscall.EISCONN: return nil default: diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/interface.go b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/interface.go index ae2cd0fc7..dae96c574 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/interface.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/interface.go @@ -71,16 +71,16 @@ type Dialer struct { // Returns a net.Conn created from a file discriptor for a socket // with SO_REUSEPORT and SO_REUSEADDR option set. func (d *Dialer) Dial(network, address string) (net.Conn, error) { - // there's a rare case where dial returns successfully but for some reason the - // RemoteAddr is not yet set. We wait here a while until it is, and if too long - // passes, we fail. c, err := dial(d.D, network, address) if err != nil { return nil, err } + // there's a rare case where dial returns successfully but for some reason the + // RemoteAddr is not yet set. We wait here a while until it is, and if too long + // passes, we fail. This is horrendous. for start := time.Now(); c.RemoteAddr() == nil; { - if time.Now().Sub(start) > time.Second { + if time.Now().Sub(start) > (time.Millisecond * 500) { c.Close() return nil, ErrReuseFailed }