Commit 9062b9fe authored by Juan Batiz-Benet's avatar Juan Batiz-Benet

connect timing fixes to reuseport

parent 7a3e0cdc
...@@ -160,7 +160,7 @@ ...@@ -160,7 +160,7 @@
}, },
{ {
"ImportPath": "github.com/jbenet/go-reuseport", "ImportPath": "github.com/jbenet/go-reuseport",
"Rev": "f2ab96a83e1b33b66478eedd314884755d771933" "Rev": "1e1968c4744fef51234e83f015aa0187b4bd796b"
}, },
{ {
"ImportPath": "github.com/jbenet/go-sockaddr/net", "ImportPath": "github.com/jbenet/go-sockaddr/net",
......
...@@ -106,6 +106,9 @@ func dial(dialer net.Dialer, netw, addr string) (c net.Conn, err error) { ...@@ -106,6 +106,9 @@ func dial(dialer net.Dialer, netw, addr string) (c net.Conn, err error) {
} }
} }
// 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 { if fd, err = socket(rfamily, socktype, rprotocol); err != nil {
return nil, err return nil, err
} }
...@@ -118,6 +121,12 @@ func dial(dialer net.Dialer, netw, addr string) (c net.Conn, err error) { ...@@ -118,6 +121,12 @@ func dial(dialer net.Dialer, netw, addr string) (c net.Conn, err error) {
if err = connect(fd, remoteSockaddr); err != nil { if err = connect(fd, remoteSockaddr); err != nil {
syscall.Close(fd) syscall.Close(fd)
// fmt.Println("connect failed", localSockaddr, err) // fmt.Println("connect failed", localSockaddr, err)
continue // try again.
}
break
}
if err != nil {
return nil, err return nil, err
} }
...@@ -314,6 +323,7 @@ func connect(fd int, ra syscall.Sockaddr) error { ...@@ -314,6 +323,7 @@ func connect(fd int, ra syscall.Sockaddr) error {
} }
var err error var err error
start := time.Now()
for { for {
// if err := fd.pd.WaitWrite(); err != nil { // if err := fd.pd.WaitWrite(); err != nil {
// return err // return err
...@@ -321,7 +331,8 @@ func connect(fd int, ra syscall.Sockaddr) error { ...@@ -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... // 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 // 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!? // 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 var nerr int
nerr, err = syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_ERROR) nerr, err = syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_ERROR)
if err != nil { if err != nil {
...@@ -329,6 +340,10 @@ func connect(fd int, ra syscall.Sockaddr) error { ...@@ -329,6 +340,10 @@ func connect(fd int, ra syscall.Sockaddr) error {
} }
switch err = syscall.Errno(nerr); err { switch err = syscall.Errno(nerr); err {
case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR: 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: case syscall.Errno(0), syscall.EISCONN:
return nil return nil
default: default:
......
...@@ -71,16 +71,16 @@ type Dialer struct { ...@@ -71,16 +71,16 @@ type Dialer struct {
// Returns a net.Conn created from a file discriptor for a socket // Returns a net.Conn created from a file discriptor for a socket
// with SO_REUSEPORT and SO_REUSEADDR option set. // with SO_REUSEPORT and SO_REUSEADDR option set.
func (d *Dialer) Dial(network, address string) (net.Conn, error) { 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) c, err := dial(d.D, network, address)
if err != nil { if err != nil {
return nil, err 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; { for start := time.Now(); c.RemoteAddr() == nil; {
if time.Now().Sub(start) > time.Second { if time.Now().Sub(start) > (time.Millisecond * 500) {
c.Close() c.Close()
return nil, ErrReuseFailed return nil, ErrReuseFailed
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment