fix: disallow dialFunc be called after grpc transport has be closed

This commit is contained in:
wwqgtxx 2025-04-04 13:33:00 +08:00
parent efa224373f
commit 24a9ff6d03
3 changed files with 26 additions and 7 deletions

View File

@ -46,7 +46,7 @@ type Conn struct {
reader io.ReadCloser reader io.ReadCloser
once sync.Once once sync.Once
close atomic.Bool closed atomic.Bool
err error err error
remain int remain int
br *bufio.Reader br *bufio.Reader
@ -71,7 +71,7 @@ func (g *Conn) initReader() {
} }
g.netAddr = addr g.netAddr = addr
if !g.close.Load() { if !g.closed.Load() {
g.reader = reader g.reader = reader
g.br = bufio.NewReader(reader) g.br = bufio.NewReader(reader)
} else { } else {
@ -184,7 +184,7 @@ func (g *Conn) FrontHeadroom() int {
} }
func (g *Conn) Close() error { func (g *Conn) Close() error {
g.close.Store(true) g.closed.Store(true)
var errorArr []error var errorArr []error
if reader := g.reader; reader != nil { if reader := g.reader; reader != nil {
@ -224,7 +224,11 @@ func (g *Conn) SetDeadline(t time.Time) error {
} }
func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string, realityConfig *tlsC.RealityConfig) *TransportWrap { func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string, realityConfig *tlsC.RealityConfig) *TransportWrap {
closed := &atomic.Bool{}
dialFunc := func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) { dialFunc := func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
if closed.Load() {
return nil, errors.New("transport closed")
}
pconn, err := dialFn(ctx, network, addr) pconn, err := dialFn(ctx, network, addr)
if err != nil { if err != nil {
return nil, err return nil, err
@ -289,6 +293,7 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string, re
} }
wrap := &TransportWrap{ wrap := &TransportWrap{
Transport: transport, Transport: transport,
closed: closed,
} }
return wrap return wrap
} }

View File

@ -1,12 +1,16 @@
package gun package gun
import ( import (
"golang.org/x/net/http2"
"net" "net"
"github.com/metacubex/mihomo/common/atomic"
"golang.org/x/net/http2"
) )
type TransportWrap struct { type TransportWrap struct {
*http2.Transport *http2.Transport
closed *atomic.Bool
} }
type netAddr struct { type netAddr struct {

View File

@ -11,9 +11,13 @@ import (
) )
type clientConnPool struct { type clientConnPool struct {
t *http2.Transport t *http2.Transport
mu sync.Mutex
conns map[string][]*http2.ClientConn // key is host:port mu sync.Mutex
conns map[string][]*http2.ClientConn // key is host:port
dialing map[string]unsafe.Pointer // currently in-flight dials
keys map[*http2.ClientConn][]string
addConnCalls map[string]unsafe.Pointer // in-flight addConnIfNeeded calls
} }
type clientConn struct { type clientConn struct {
@ -42,6 +46,9 @@ func closeClientConn(cc *http2.ClientConn) { // like forceCloseConn() in http2.C
} }
func (tw *TransportWrap) Close() error { func (tw *TransportWrap) Close() error {
if tw.closed.Swap(true) {
return nil // already closed
}
connPool := transportConnPool(tw.Transport) connPool := transportConnPool(tw.Transport)
p := (*clientConnPool)((*efaceWords)(unsafe.Pointer(&connPool)).data) p := (*clientConnPool)((*efaceWords)(unsafe.Pointer(&connPool)).data)
p.mu.Lock() p.mu.Lock()
@ -51,6 +58,9 @@ func (tw *TransportWrap) Close() error {
closeClientConn(cc) closeClientConn(cc)
} }
} }
// cleanup
p.conns = make(map[string][]*http2.ClientConn)
p.keys = make(map[*http2.ClientConn][]string)
return nil return nil
} }