@cryptotaxi247 / kubo / commits / 9062b9fe6

connect timing fixes to reuseport

Juan Batiz-Benet committed Jan 19, 2015 at 16:56 UTC 9062b9fe6cae78e3b6e24903d9368ea7dffd45fd
3 files changed +31 -16
Godeps/Godeps.json
+1 -1
@@ -160,7 +160,7 @@
160 },
161 {
162 "ImportPath": "github.com/jbenet/go-reuseport",
163 - "Rev": "f2ab96a83e1b33b66478eedd314884755d771933"
163 + "Rev": "1e1968c4744fef51234e83f015aa0187b4bd796b"
164 },
165 {
166 "ImportPath": "github.com/jbenet/go-sockaddr/net",
Godeps/_workspace/src/github.com/jbenet/go-reuseport/impl_unix.go
+26 -11
@@ -106,18 +106,27 @@ func dial(dialer net.Dialer, netw, addr string) (c net.Conn, err error) {
106 }
107 }
108
109 - if fd, err = socket(rfamily, socktype, rprotocol); err != nil {
110 - return nil, err
111 - }
109 + // look at dialTCP in http://golang.org/src/net/tcpsock_posix.go .... !
110 + // here we just try again 3 times.
111 + for i := 0; i < 3; i++ {
112 + if fd, err = socket(rfamily, socktype, rprotocol); err != nil {
113 + return nil, err
114 + }
115
113 - if err = syscall.Bind(fd, localSockaddr); err != nil {
114 - // fmt.Println("bind failed")
115 - syscall.Close(fd)
116 - return nil, err
116 + if err = syscall.Bind(fd, localSockaddr); err != nil {
117 + // fmt.Println("bind failed")
118 + syscall.Close(fd)
119 + return nil, err
120 + }
121 + if err = connect(fd, remoteSockaddr); err != nil {
122 + syscall.Close(fd)
123 + // fmt.Println("connect failed", localSockaddr, err)
124 + continue // try again.
125 + }
126 +
127 + break
128 }
118 - if err = connect(fd, remoteSockaddr); err != nil {
119 - syscall.Close(fd)
120 - // fmt.Println("connect failed", localSockaddr, err)
129 + if err != nil {
130 return nil, err
131 }
132
@@ -314,6 +323,7 @@ func connect(fd int, ra syscall.Sockaddr) error {
323 }
324
325 var err error
326 + start := time.Now()
327 for {
328 // if err := fd.pd.WaitWrite(); err != nil {
329 // return err
@@ -321,7 +331,8 @@ func connect(fd int, ra syscall.Sockaddr) error {
331 // i'd use the above fd.pd.WaitWrite to poll io correctly, just like net sockets...
332 // but of course, it uses fucking runtime_* functions that _cannot_ be used by
333 // non-go-stdlib source... seriously guys, what kind of bullshit is that!?
324 - <-time.After(20 * time.Microsecond)
334 + // we're relegated to using syscall.Select (what nightmare that is) or using
335 + // a simple but totally bogus time-based wait. garbage.
336 var nerr int
337 nerr, err = syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_ERROR)
338 if err != nil {
@@ -329,6 +340,10 @@ func connect(fd int, ra syscall.Sockaddr) error {
340 }
341 switch err = syscall.Errno(nerr); err {
342 case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
343 + if time.Now().Sub(start) > time.Second {
344 + return err
345 + }
346 + <-time.After(20 * time.Microsecond)
347 case syscall.Errno(0), syscall.EISCONN:
348 return nil
349 default:
Godeps/_workspace/src/github.com/jbenet/go-reuseport/interface.go
+4 -4
@@ -71,16 +71,16 @@ type Dialer struct {
71 // Returns a net.Conn created from a file discriptor for a socket
72 // with SO_REUSEPORT and SO_REUSEADDR option set.
73 func (d *Dialer) Dial(network, address string) (net.Conn, error) {
74 - // there's a rare case where dial returns successfully but for some reason the
75 - // RemoteAddr is not yet set. We wait here a while until it is, and if too long
76 - // passes, we fail.
74 c, err := dial(d.D, network, address)
75 if err != nil {
76 return nil, err
77 }
78
79 + // there's a rare case where dial returns successfully but for some reason the
80 + // RemoteAddr is not yet set. We wait here a while until it is, and if too long
81 + // passes, we fail. This is horrendous.
82 for start := time.Now(); c.RemoteAddr() == nil; {
83 - if time.Now().Sub(start) > time.Second {
83 + if time.Now().Sub(start) > (time.Millisecond * 500) {
84 c.Close()
85 return nil, ErrReuseFailed
86 }