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 ""