提交 bf1690f4 作者: Juan Batiz-Benet

fixed fd leaks in go-reuseport

上级 343940da
...@@ -160,7 +160,7 @@ ...@@ -160,7 +160,7 @@
}, },
{ {
"ImportPath": "github.com/jbenet/go-reuseport", "ImportPath": "github.com/jbenet/go-reuseport",
"Rev": "6924153aded2d61c89a83c8f0738ed4e8df9191f" "Rev": "096958438ae3683c9f3c8ae0f7139b5ce600e6a8"
}, },
{ {
"ImportPath": "github.com/jbenet/go-sockaddr/net", "ImportPath": "github.com/jbenet/go-sockaddr/net",
......
...@@ -18,15 +18,3 @@ func ResolveAddr(network, address string) (net.Addr, error) { ...@@ -18,15 +18,3 @@ func ResolveAddr(network, address string) (net.Addr, error) {
return net.ResolveUnixAddr(network, address) return net.ResolveUnixAddr(network, address)
} }
} }
// conn is a struct that stores a raddr to get around:
// * https://github.com/golang/go/issues/9661#issuecomment-71043147
// * https://gist.github.com/jbenet/5c191d698fe9ec58c49d
type conn struct {
net.Conn
raddr net.Addr
}
func (c *conn) RemoteAddr() net.Addr {
return c.raddr
}
...@@ -163,6 +163,7 @@ func dial(dialer net.Dialer, netw, addr string) (c net.Conn, err error) { ...@@ -163,6 +163,7 @@ func dial(dialer net.Dialer, netw, addr string) (c net.Conn, err error) {
if err = file.Close(); err != nil { if err = file.Close(); err != nil {
syscall.Close(fd) syscall.Close(fd)
c.Close()
return nil, err return nil, err
} }
...@@ -170,19 +171,6 @@ func dial(dialer net.Dialer, netw, addr string) (c net.Conn, err error) { ...@@ -170,19 +171,6 @@ func dial(dialer net.Dialer, netw, addr string) (c net.Conn, err error) {
return c, err return c, err
} }
// there's a rare case where dial returns successfully but for some reason the
// RemoteAddr is not yet set. So, since we know what raddr should be, we just
// wrap it. This is not ideal in that sometimes getpeername() may return a
// different addr. But until this is fixed, best way to do it.
// * https://gist.github.com/jbenet/5c191d698fe9ec58c49d
// * https://github.com/golang/go/issues/9661#issuecomment-71043147
func wrapConnWithRemoteAddr(c net.Conn, raddr net.Addr) net.Conn {
if c.RemoteAddr() == nil {
return &conn{Conn: c, raddr: raddr}
}
return c // it's fine, no need to wrap.
}
func listen(netw, addr string) (fd int, err error) { func listen(netw, addr string) (fd int, err error) {
var ( var (
family int family int
...@@ -256,6 +244,7 @@ func listenStream(netw, addr string) (l net.Listener, err error) { ...@@ -256,6 +244,7 @@ func listenStream(netw, addr string) (l net.Listener, err error) {
if err = file.Close(); err != nil { if err = file.Close(); err != nil {
syscall.Close(fd) syscall.Close(fd)
l.Close()
return nil, err return nil, err
} }
...@@ -280,6 +269,7 @@ func listenPacket(netw, addr string) (p net.PacketConn, err error) { ...@@ -280,6 +269,7 @@ func listenPacket(netw, addr string) (p net.PacketConn, err error) {
if err = file.Close(); err != nil { if err = file.Close(); err != nil {
syscall.Close(fd) syscall.Close(fd)
p.Close()
return nil, err return nil, err
} }
...@@ -327,6 +317,7 @@ func connect(fd int, ra syscall.Sockaddr, deadline time.Time) error { ...@@ -327,6 +317,7 @@ func connect(fd int, ra syscall.Sockaddr, deadline time.Time) error {
if err != nil { if err != nil {
return err return err
} }
defer poller.Close()
for { for {
if err = poller.WaitWrite(deadline); err != nil { if err = poller.WaitWrite(deadline); err != nil {
......
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
"io" "io"
"net" "net"
"os" "os"
"os/exec"
"strings" "strings"
"sync" "sync"
"testing" "testing"
...@@ -19,6 +20,7 @@ func echo(c net.Conn) { ...@@ -19,6 +20,7 @@ func echo(c net.Conn) {
} }
func packetEcho(c net.PacketConn) { func packetEcho(c net.PacketConn) {
defer c.Close()
buf := make([]byte, 65536) buf := make([]byte, 65536)
for { for {
n, addr, err := c.ReadFrom(buf) n, addr, err := c.ReadFrom(buf)
...@@ -501,8 +503,8 @@ func TestDialRespectsTimeout(t *testing.T) { ...@@ -501,8 +503,8 @@ func TestDialRespectsTimeout(t *testing.T) {
go func() { go func() {
c, err := d.Dial(network, raddr) c, err := d.Dial(network, raddr)
if err == nil { if err == nil {
errs <- errors.New("should've not connected")
c.Close() c.Close()
errs <- errors.New("should've not connected")
return return
} }
close(errs) // success! close(errs) // success!
...@@ -534,14 +536,37 @@ func TestUnixNotSupported(t *testing.T) { ...@@ -534,14 +536,37 @@ func TestUnixNotSupported(t *testing.T) {
addr := tcase[1] addr := tcase[1]
t.Log("testing", network, addr) t.Log("testing", network, addr)
_, err := Listen(network, addr) l, err := Listen(network, addr)
if err == nil { if err == nil {
l.Close()
t.Fatal("unix supported") t.Fatal("unix supported")
continue continue
} }
} }
} }
func TestOpenFDs(t *testing.T) {
// this is a totally ad-hoc limit. test harnesses may add fds.
// but if this is really much higher than 20, there's obviously leaks.
limit := 20
start := time.Now()
for countOpenFiles(t) > limit {
<-time.After(time.Second)
t.Log("open fds:", countOpenFiles(t))
if time.Now().Sub(start) > (time.Second * 15) {
t.Error("fd leak!")
}
}
}
func countOpenFiles(t *testing.T) int {
out, err := exec.Command("/bin/sh", "-c", fmt.Sprintf("lsof -p %v", os.Getpid())).Output()
if err != nil {
t.Fatal(err)
}
return bytes.Count(out, []byte("\n"))
}
func getPort(a net.Addr) string { func getPort(a net.Addr) string {
if a == nil { if a == nil {
return "" return ""
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论