@cryptotaxi247 / kubo / commits / bf1690f42

fixed fd leaks in go-reuseport

Juan Batiz-Benet committed Jan 23, 2015 at 16:17 UTC bf1690f42e72a4b60c552babdf6b3fb7cf03dcc3
4 files changed +32 -28
Godeps/Godeps.json
+1 -1
@@ -160,7 +160,7 @@
160 },
161 {
162 "ImportPath": "github.com/jbenet/go-reuseport",
163 - "Rev": "6924153aded2d61c89a83c8f0738ed4e8df9191f"
163 + "Rev": "096958438ae3683c9f3c8ae0f7139b5ce600e6a8"
164 },
165 {
166 "ImportPath": "github.com/jbenet/go-sockaddr/net",
Godeps/_workspace/src/github.com/jbenet/go-reuseport/addr.go
-12
@@ -18,15 +18,3 @@ func ResolveAddr(network, address string) (net.Addr, error) {
18 return net.ResolveUnixAddr(network, address)
19 }
20 }
21 -
22 -// conn is a struct that stores a raddr to get around:
23 -// * https://github.com/golang/go/issues/9661#issuecomment-71043147
24 -// * https://gist.github.com/jbenet/5c191d698fe9ec58c49d
25 -type conn struct {
26 - net.Conn
27 - raddr net.Addr
28 -}
29 -
30 -func (c *conn) RemoteAddr() net.Addr {
31 - return c.raddr
32 -}
Godeps/_workspace/src/github.com/jbenet/go-reuseport/impl_unix.go
+4 -13
@@ -163,6 +163,7 @@ func dial(dialer net.Dialer, netw, addr string) (c net.Conn, err error) {
163
164 if err = file.Close(); err != nil {
165 syscall.Close(fd)
166 + c.Close()
167 return nil, err
168 }
169
@@ -170,19 +171,6 @@ func dial(dialer net.Dialer, netw, addr string) (c net.Conn, err error) {
171 return c, err
172 }
173
173 -// there's a rare case where dial returns successfully but for some reason the
174 -// RemoteAddr is not yet set. So, since we know what raddr should be, we just
175 -// wrap it. This is not ideal in that sometimes getpeername() may return a
176 -// different addr. But until this is fixed, best way to do it.
177 -// * https://gist.github.com/jbenet/5c191d698fe9ec58c49d
178 -// * https://github.com/golang/go/issues/9661#issuecomment-71043147
179 -func wrapConnWithRemoteAddr(c net.Conn, raddr net.Addr) net.Conn {
180 - if c.RemoteAddr() == nil {
181 - return &conn{Conn: c, raddr: raddr}
182 - }
183 - return c // it's fine, no need to wrap.
184 -}
185 -
174 func listen(netw, addr string) (fd int, err error) {
175 var (
176 family int
@@ -256,6 +244,7 @@ func listenStream(netw, addr string) (l net.Listener, err error) {
244
245 if err = file.Close(); err != nil {
246 syscall.Close(fd)
247 + l.Close()
248 return nil, err
249 }
250
@@ -280,6 +269,7 @@ func listenPacket(netw, addr string) (p net.PacketConn, err error) {
269
270 if err = file.Close(); err != nil {
271 syscall.Close(fd)
272 + p.Close()
273 return nil, err
274 }
275
@@ -327,6 +317,7 @@ func connect(fd int, ra syscall.Sockaddr, deadline time.Time) error {
317 if err != nil {
318 return err
319 }
320 + defer poller.Close()
321
322 for {
323 if err = poller.WaitWrite(deadline); err != nil {
Godeps/_workspace/src/github.com/jbenet/go-reuseport/reuse_test.go
+27 -2
@@ -7,6 +7,7 @@ import (
7 "io"
8 "net"
9 "os"
10 + "os/exec"
11 "strings"
12 "sync"
13 "testing"
@@ -19,6 +20,7 @@ func echo(c net.Conn) {
20 }
21
22 func packetEcho(c net.PacketConn) {
23 + defer c.Close()
24 buf := make([]byte, 65536)
25 for {
26 n, addr, err := c.ReadFrom(buf)
@@ -501,8 +503,8 @@ func TestDialRespectsTimeout(t *testing.T) {
503 go func() {
504 c, err := d.Dial(network, raddr)
505 if err == nil {
504 - errs <- errors.New("should've not connected")
506 c.Close()
507 + errs <- errors.New("should've not connected")
508 return
509 }
510 close(errs) // success!
@@ -534,14 +536,37 @@ func TestUnixNotSupported(t *testing.T) {
536 addr := tcase[1]
537 t.Log("testing", network, addr)
538
537 - _, err := Listen(network, addr)
539 + l, err := Listen(network, addr)
540 if err == nil {
541 + l.Close()
542 t.Fatal("unix supported")
543 continue
544 }
545 }
546 }
547
548 +func TestOpenFDs(t *testing.T) {
549 + // this is a totally ad-hoc limit. test harnesses may add fds.
550 + // but if this is really much higher than 20, there's obviously leaks.
551 + limit := 20
552 + start := time.Now()
553 + for countOpenFiles(t) > limit {
554 + <-time.After(time.Second)
555 + t.Log("open fds:", countOpenFiles(t))
556 + if time.Now().Sub(start) > (time.Second * 15) {
557 + t.Error("fd leak!")
558 + }
559 + }
560 +}
561 +
562 +func countOpenFiles(t *testing.T) int {
563 + out, err := exec.Command("/bin/sh", "-c", fmt.Sprintf("lsof -p %v", os.Getpid())).Output()
564 + if err != nil {
565 + t.Fatal(err)
566 + }
567 + return bytes.Count(out, []byte("\n"))
568 +}
569 +
570 func getPort(a net.Addr) string {
571 if a == nil {
572 return ""