Fixed bug where tried closing a single net.Conn multiple times.
This commit is contained in:
parent
d2cac01b63
commit
325901c2c3
18
dialer.go
18
dialer.go
|
@ -2,6 +2,7 @@ package goadb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
|
@ -66,17 +67,22 @@ func (d *netDialer) Dial() (*wire.Conn, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
conn := &wire.Conn{
|
// net.Conn can't be closed more than once, but wire.Conn will try to close both sender and scanner
|
||||||
Scanner: wire.NewScanner(netConn),
|
// so we need to wrap it to make it safe.
|
||||||
Sender: wire.NewSender(netConn),
|
safeConn := wire.MultiCloseable(netConn)
|
||||||
}
|
|
||||||
|
|
||||||
// Prevent leaking the network connection, not sure if TCPConn does this itself.
|
// Prevent leaking the network connection, not sure if TCPConn does this itself.
|
||||||
runtime.SetFinalizer(netConn, func(conn *net.TCPConn) {
|
// Note that the network connection may still be in use after the conn isn't (scanners/senders
|
||||||
|
// can give their underlying connections to other scanner/sender types), so we can't
|
||||||
|
// set the finalizer on conn.
|
||||||
|
runtime.SetFinalizer(safeConn, func(conn io.ReadWriteCloser) {
|
||||||
conn.Close()
|
conn.Close()
|
||||||
})
|
})
|
||||||
|
|
||||||
return conn, nil
|
return &wire.Conn{
|
||||||
|
Scanner: wire.NewScanner(safeConn),
|
||||||
|
Sender: wire.NewSender(safeConn),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func roundTripSingleResponse(d Dialer, req string) ([]byte, error) {
|
func roundTripSingleResponse(d Dialer, req string) ([]byte, error) {
|
||||||
|
|
|
@ -66,7 +66,7 @@ func (w *syncFileWriter) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := w.sender.SendOctetString(wire.StatusSyncDone); err != nil {
|
if err := w.sender.SendOctetString(wire.StatusSyncDone); err != nil {
|
||||||
return util.WrapErrf(err, "error closing file writer")
|
return util.WrapErrf(err, "error sending done chunk to close stream")
|
||||||
}
|
}
|
||||||
if err := w.sender.SendTime(w.mtime); err != nil {
|
if err := w.sender.SendTime(w.mtime); err != nil {
|
||||||
return util.WrapErrf(err, "error writing file modification time")
|
return util.WrapErrf(err, "error writing file modification time")
|
||||||
|
|
20
wire/util.go
20
wire/util.go
|
@ -5,6 +5,8 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/zach-klippenstein/goadb/util"
|
"github.com/zach-klippenstein/goadb/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -80,3 +82,21 @@ func writeFully(w io.Writer, data []byte) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MultiCloseable wraps c in a ReadWriteCloser that can be safely closed multiple times.
|
||||||
|
func MultiCloseable(c io.ReadWriteCloser) io.ReadWriteCloser {
|
||||||
|
return &multiCloseable{ReadWriteCloser: c}
|
||||||
|
}
|
||||||
|
|
||||||
|
type multiCloseable struct {
|
||||||
|
io.ReadWriteCloser
|
||||||
|
closeOnce sync.Once
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *multiCloseable) Close() error {
|
||||||
|
c.closeOnce.Do(func() {
|
||||||
|
c.err = c.ReadWriteCloser.Close()
|
||||||
|
})
|
||||||
|
return c.err
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue