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
once sync.Once
close atomic.Bool
closed atomic.Bool
err error
remain int
br *bufio.Reader
@ -71,7 +71,7 @@ func (g *Conn) initReader() {
}
g.netAddr = addr
if !g.close.Load() {
if !g.closed.Load() {
g.reader = reader
g.br = bufio.NewReader(reader)
} else {
@ -184,7 +184,7 @@ func (g *Conn) FrontHeadroom() int {
}
func (g *Conn) Close() error {
g.close.Store(true)
g.closed.Store(true)
var errorArr []error
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 {
closed := &atomic.Bool{}
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)
if err != nil {
return nil, err
@ -289,6 +293,7 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string, re
}
wrap := &TransportWrap{
Transport: transport,
closed: closed,
}
return wrap
}

View file

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

View file

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