Fix reset outbounds

This commit is contained in:
世界 2024-07-07 15:45:50 +08:00
parent 6144c8e340
commit 98ff897f35
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
13 changed files with 92 additions and 15 deletions

View file

@ -22,4 +22,5 @@ type V2RayServerTransportHandler interface {
type V2RayClientTransport interface { type V2RayClientTransport interface {
DialContext(ctx context.Context) (net.Conn, error) DialContext(ctx context.Context) (net.Conn, error)
Close() error
} }

View file

@ -130,8 +130,8 @@ func (h *Hysteria) NewPacketConnection(ctx context.Context, conn N.PacketConn, m
return NewPacketConnection(ctx, h, conn, metadata) return NewPacketConnection(ctx, h, conn, metadata)
} }
func (h *Hysteria) InterfaceUpdated() error { func (h *Hysteria) InterfaceUpdated() {
return h.client.CloseWithError(E.New("network changed")) h.client.CloseWithError(E.New("network changed"))
} }
func (h *Hysteria) Close() error { func (h *Hysteria) Close() error {

View file

@ -116,8 +116,8 @@ func (h *Hysteria2) NewPacketConnection(ctx context.Context, conn N.PacketConn,
return NewPacketConnection(ctx, h, conn, metadata) return NewPacketConnection(ctx, h, conn, metadata)
} }
func (h *Hysteria2) InterfaceUpdated() error { func (h *Hysteria2) InterfaceUpdated() {
return h.client.CloseWithError(E.New("network changed")) h.client.CloseWithError(E.New("network changed"))
} }
func (h *Hysteria2) Close() error { func (h *Hysteria2) Close() error {

View file

@ -108,6 +108,9 @@ func (h *Trojan) NewPacketConnection(ctx context.Context, conn N.PacketConn, met
} }
func (h *Trojan) InterfaceUpdated() { func (h *Trojan) InterfaceUpdated() {
if h.transport != nil {
h.transport.Close()
}
if h.multiplexDialer != nil { if h.multiplexDialer != nil {
h.multiplexDialer.Reset() h.multiplexDialer.Reset()
} }

View file

@ -127,6 +127,9 @@ func (h *VLESS) NewPacketConnection(ctx context.Context, conn N.PacketConn, meta
} }
func (h *VLESS) InterfaceUpdated() { func (h *VLESS) InterfaceUpdated() {
if h.transport != nil {
h.transport.Close()
}
if h.multiplexDialer != nil { if h.multiplexDialer != nil {
h.multiplexDialer.Reset() h.multiplexDialer.Reset()
} }

View file

@ -103,6 +103,9 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg
} }
func (h *VMess) InterfaceUpdated() { func (h *VMess) InterfaceUpdated() {
if h.transport != nil {
h.transport.Close()
}
if h.multiplexDialer != nil { if h.multiplexDialer != nil {
h.multiplexDialer.Reset() h.multiplexDialer.Reset()
} }

View file

@ -72,12 +72,6 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt
}, nil }, nil
} }
func (c *Client) Close() error {
return common.Close(
common.PtrOrNil(c.conn),
)
}
func (c *Client) connect() (*grpc.ClientConn, error) { func (c *Client) connect() (*grpc.ClientConn, error) {
conn := c.conn conn := c.conn
if conn != nil && conn.GetState() != connectivity.Shutdown { if conn != nil && conn.GetState() != connectivity.Shutdown {
@ -113,3 +107,13 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
} }
return NewGRPCConn(stream, cancel), nil return NewGRPCConn(stream, cancel), nil
} }
func (c *Client) Close() error {
c.connAccess.Lock()
defer c.connAccess.Unlock()
if c.conn != nil {
c.conn.Close()
c.conn = nil
}
return nil
}

View file

@ -109,8 +109,6 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
} }
func (c *Client) Close() error { func (c *Client) Close() error {
if c.transport != nil { v2rayhttp.ResetTransport(c.transport)
v2rayhttp.CloseIdleConnections(c.transport)
}
return nil return nil
} }

View file

@ -155,6 +155,6 @@ func (c *Client) dialHTTP2(ctx context.Context) (net.Conn, error) {
} }
func (c *Client) Close() error { func (c *Client) Close() error {
CloseIdleConnections(c.transport) c.transport = ResetTransport(c.transport)
return nil return nil
} }

View file

@ -0,0 +1,47 @@
package v2rayhttp
import (
"net/http"
"reflect"
"sync"
"unsafe"
E "github.com/sagernet/sing/common/exceptions"
"golang.org/x/net/http2"
)
type clientConnPool struct {
t *http2.Transport
mu sync.Mutex
conns map[string][]*http2.ClientConn // key is host:port
}
type efaceWords struct {
typ unsafe.Pointer
data unsafe.Pointer
}
func ResetTransport(rawTransport http.RoundTripper) http.RoundTripper {
switch transport := rawTransport.(type) {
case *http.Transport:
transport.CloseIdleConnections()
return transport.Clone()
case *http2.Transport:
connPool := transportConnPool(transport)
p := (*clientConnPool)((*efaceWords)(unsafe.Pointer(&connPool)).data)
p.mu.Lock()
defer p.mu.Unlock()
for _, vv := range p.conns {
for _, cc := range vv {
cc.Close()
}
}
return transport
default:
panic(E.New("unknown transport type: ", reflect.TypeOf(transport)))
}
}
//go:linkname transportConnPool golang.org/x/net/http2.(*Transport).connPool
func transportConnPool(t *http2.Transport) http2.ClientConnPool

View file

@ -116,3 +116,7 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
} }
return conn, nil return conn, nil
} }
func (c *Client) Close() error {
return nil
}

View file

@ -97,5 +97,15 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
} }
func (c *Client) Close() error { func (c *Client) Close() error {
return common.Close(c.conn, c.rawConn) c.connAccess.Lock()
defer c.connAccess.Unlock()
if c.conn != nil {
c.conn.CloseWithError(0, "")
}
if c.rawConn != nil {
c.rawConn.Close()
}
c.conn = nil
c.rawConn = nil
return nil
} }

View file

@ -127,3 +127,7 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
return &EarlyWebsocketConn{Client: c, ctx: ctx, create: make(chan struct{})}, nil return &EarlyWebsocketConn{Client: c, ctx: ctx, create: make(chan struct{})}, nil
} }
} }
func (c *Client) Close() error {
return nil
}