mirror of
https://github.com/libp2p/go-reuseport.git
synced 2025-09-26 19:01:11 +08:00
fixed fd leaks
This commit is contained in:
12
addr.go
12
addr.go
@@ -18,15 +18,3 @@ func ResolveAddr(network, address string) (net.Addr, error) {
|
||||
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
|
||||
}
|
||||
|
17
impl_unix.go
17
impl_unix.go
@@ -163,6 +163,7 @@ func dial(dialer net.Dialer, netw, addr string) (c net.Conn, err error) {
|
||||
|
||||
if err = file.Close(); err != nil {
|
||||
syscall.Close(fd)
|
||||
c.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -170,19 +171,6 @@ func dial(dialer net.Dialer, netw, addr string) (c net.Conn, err error) {
|
||||
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) {
|
||||
var (
|
||||
family int
|
||||
@@ -256,6 +244,7 @@ func listenStream(netw, addr string) (l net.Listener, err error) {
|
||||
|
||||
if err = file.Close(); err != nil {
|
||||
syscall.Close(fd)
|
||||
l.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -280,6 +269,7 @@ func listenPacket(netw, addr string) (p net.PacketConn, err error) {
|
||||
|
||||
if err = file.Close(); err != nil {
|
||||
syscall.Close(fd)
|
||||
p.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -327,6 +317,7 @@ func connect(fd int, ra syscall.Sockaddr, deadline time.Time) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer poller.Close()
|
||||
|
||||
for {
|
||||
if err = poller.WaitWrite(deadline); err != nil {
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -19,6 +20,7 @@ func echo(c net.Conn) {
|
||||
}
|
||||
|
||||
func packetEcho(c net.PacketConn) {
|
||||
defer c.Close()
|
||||
buf := make([]byte, 65536)
|
||||
for {
|
||||
n, addr, err := c.ReadFrom(buf)
|
||||
@@ -501,8 +503,8 @@ func TestDialRespectsTimeout(t *testing.T) {
|
||||
go func() {
|
||||
c, err := d.Dial(network, raddr)
|
||||
if err == nil {
|
||||
errs <- errors.New("should've not connected")
|
||||
c.Close()
|
||||
errs <- errors.New("should've not connected")
|
||||
return
|
||||
}
|
||||
close(errs) // success!
|
||||
@@ -534,14 +536,37 @@ func TestUnixNotSupported(t *testing.T) {
|
||||
addr := tcase[1]
|
||||
t.Log("testing", network, addr)
|
||||
|
||||
_, err := Listen(network, addr)
|
||||
l, err := Listen(network, addr)
|
||||
if err == nil {
|
||||
l.Close()
|
||||
t.Fatal("unix supported")
|
||||
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 {
|
||||
if a == nil {
|
||||
return ""
|
||||
|
Reference in New Issue
Block a user