Improve idle connection management

This commit is contained in:
世界
2026-10-02 18:00:09 +08:00
parent eb7deeae8a
commit 07130365d1
37 changed files with 766 additions and 181 deletions
+12 -4
View File
@@ -13,7 +13,6 @@ import (
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/protocol/tuic"
"github.com/sagernet/sing-quic/hysteria"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/bufio"
@@ -28,9 +27,10 @@ func RegisterOutbound(registry *outbound.Registry) {
}
var (
_ adapter.Outbound = (*tuic.Outbound)(nil)
_ adapter.InterfaceUpdateListener = (*tuic.Outbound)(nil)
_ adapter.IdleConnectionCloser = (*Outbound)(nil)
_ adapter.Outbound = (*Outbound)(nil)
_ adapter.InterfaceUpdateListener = (*Outbound)(nil)
_ adapter.IdleConnectionKeeper = (*Outbound)(nil)
_ adapter.OutboundWithMultiplex = (*Outbound)(nil)
)
type Outbound struct {
@@ -119,6 +119,14 @@ func (h *Outbound) InterfaceUpdated(ctx context.Context) {
h.client.CloseWithError(E.New("network changed"))
}
func (h *Outbound) MultiplexEnabled() bool {
return true
}
func (h *Outbound) SetKeepIdleConnections(keep bool) {
h.client.SetKeepIdleConnections(keep)
}
func (h *Outbound) CloseIdleConnections() {
h.client.CloseIdleConnections()
}
+12 -4
View File
@@ -16,7 +16,6 @@ import (
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/protocol/tuic"
qtls "github.com/sagernet/sing-quic"
"github.com/sagernet/sing-quic/hysteria"
"github.com/sagernet/sing-quic/hysteria2"
@@ -35,9 +34,10 @@ func RegisterOutbound(registry *outbound.Registry) {
}
var (
_ adapter.Outbound = (*tuic.Outbound)(nil)
_ adapter.InterfaceUpdateListener = (*tuic.Outbound)(nil)
_ adapter.IdleConnectionCloser = (*Outbound)(nil)
_ adapter.Outbound = (*Outbound)(nil)
_ adapter.InterfaceUpdateListener = (*Outbound)(nil)
_ adapter.IdleConnectionKeeper = (*Outbound)(nil)
_ adapter.OutboundWithMultiplex = (*Outbound)(nil)
)
type Outbound struct {
@@ -211,6 +211,14 @@ func (h *Outbound) InterfaceUpdated(ctx context.Context) {
h.client.CloseWithError(E.New("network changed"))
}
func (h *Outbound) MultiplexEnabled() bool {
return true
}
func (h *Outbound) SetKeepIdleConnections(keep bool) {
h.client.SetKeepIdleConnections(keep)
}
func (h *Outbound) CloseIdleConnections() {
h.client.CloseIdleConnections()
}
+7 -1
View File
@@ -29,7 +29,7 @@ func RegisterOutbound(registry *outbound.Registry) {
var (
_ adapter.OutboundWithMultiplex = (*Outbound)(nil)
_ adapter.InterfaceUpdateListener = (*Outbound)(nil)
_ adapter.IdleConnectionCloser = (*Outbound)(nil)
_ adapter.IdleConnectionKeeper = (*Outbound)(nil)
)
type Outbound struct {
@@ -140,6 +140,12 @@ func (h *Outbound) InterfaceUpdated(ctx context.Context) {
}
}
func (h *Outbound) SetKeepIdleConnections(keep bool) {
if h.multiplexDialer != nil {
h.multiplexDialer.SetKeepIdleConnections(keep)
}
}
func (h *Outbound) CloseIdleConnections() {
if h.multiplexDialer != nil {
h.multiplexDialer.CloseIdleConnections()
+13 -1
View File
@@ -30,17 +30,20 @@ type Outbound struct {
dialer N.Dialer
client snellClient
serverAddr M.Socksaddr
reuse bool
}
var (
_ adapter.InterfaceUpdateListener = (*Outbound)(nil)
_ adapter.IdleConnectionCloser = (*Outbound)(nil)
_ adapter.IdleConnectionKeeper = (*Outbound)(nil)
_ adapter.OutboundWithMultiplex = (*Outbound)(nil)
)
type snellClient interface {
snellprotocol.Method
DialContext(ctx context.Context, destination M.Socksaddr) (net.Conn, error)
Reset()
SetKeepIdleConnections(keep bool)
CloseIdleConnections()
Close() error
}
@@ -96,6 +99,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
dialer: outboundDialer,
client: client,
serverAddr: serverAddr,
reuse: options.Reuse,
}
return outbound, nil
}
@@ -147,6 +151,14 @@ func (h *Outbound) InterfaceUpdated(ctx context.Context) {
h.client.Reset()
}
func (h *Outbound) MultiplexEnabled() bool {
return h.reuse
}
func (h *Outbound) SetKeepIdleConnections(keep bool) {
h.client.SetKeepIdleConnections(keep)
}
func (h *Outbound) CloseIdleConnections() {
h.client.CloseIdleConnections()
}
+22 -14
View File
@@ -34,7 +34,8 @@ func RegisterOutbound(registry *outbound.Registry) {
var (
_ adapter.InterfaceUpdateListener = (*Outbound)(nil)
_ adapter.IdleConnectionCloser = (*Outbound)(nil)
_ adapter.IdleConnectionKeeper = (*Outbound)(nil)
_ adapter.OutboundWithMultiplex = (*Outbound)(nil)
)
type Outbound struct {
@@ -54,7 +55,7 @@ type Outbound struct {
clientConn net.Conn
client *ssh.Client
streams int
draining bool
closeIdle bool
}
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.SSHOutboundOptions) (adapter.Outbound, error) {
@@ -137,7 +138,6 @@ func (s *Outbound) connect(ctx context.Context) (client *ssh.Client, err error)
if s.client != nil {
s.streams++
s.draining = false
return s.client, nil
}
@@ -197,7 +197,6 @@ func (s *Outbound) connect(ctx context.Context) (client *ssh.Client, err error)
s.clientConn = conn
s.client = client
s.streams = 1
s.draining = false
go func() {
client.Wait()
@@ -217,14 +216,22 @@ func (s *Outbound) InterfaceUpdated(ctx context.Context) {
common.Close(s.clientConn)
}
func (s *Outbound) MultiplexEnabled() bool {
return true
}
func (s *Outbound) SetKeepIdleConnections(keep bool) {
s.clientAccess.Lock()
s.closeIdle = !keep
s.clientAccess.Unlock()
if !keep {
s.CloseIdleConnections()
}
}
func (s *Outbound) CloseIdleConnections() {
s.clientAccess.Lock()
if s.client == nil {
s.clientAccess.Unlock()
return
}
s.draining = true
if s.streams > 0 {
if s.client == nil || s.streams > 0 {
s.clientAccess.Unlock()
return
}
@@ -235,14 +242,14 @@ func (s *Outbound) CloseIdleConnections() {
common.Close(clientConn)
}
func (s *Outbound) releaseStream(client *ssh.Client) {
func (s *Outbound) releaseStream(client *ssh.Client, keepSession bool) {
s.clientAccess.Lock()
if s.client != client {
s.clientAccess.Unlock()
return
}
s.streams--
if !s.draining || s.streams > 0 {
if !s.closeIdle || keepSession || s.streams > 0 {
s.clientAccess.Unlock()
return
}
@@ -264,10 +271,11 @@ func (s *Outbound) DialContext(ctx context.Context, network string, destination
}
conn, err := client.Dial(network, destination.String())
if err != nil {
s.releaseStream(client)
s.releaseStream(client, false)
return nil, err
}
return &chanConnWrapper{Conn: conn, onClose: func() { s.releaseStream(client) }}, nil
keepSession := adapter.KeepSessionFromContext(ctx)
return &chanConnWrapper{Conn: conn, onClose: func() { s.releaseStream(client, keepSession) }}, nil
}
func (s *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
+19 -5
View File
@@ -29,7 +29,7 @@ func RegisterOutbound(registry *outbound.Registry) {
var (
_ adapter.OutboundWithMultiplex = (*Outbound)(nil)
_ adapter.InterfaceUpdateListener = (*Outbound)(nil)
_ adapter.IdleConnectionCloser = (*Outbound)(nil)
_ adapter.IdleConnectionKeeper = (*Outbound)(nil)
)
type Outbound struct {
@@ -114,7 +114,11 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
}
func (h *Outbound) MultiplexEnabled() bool {
return h.multiplexDialer != nil
if h.multiplexDialer != nil {
return true
}
multiplexTransport, isMultiplexTransport := h.transport.(adapter.V2RayMultiplexClientTransport)
return isMultiplexTransport && multiplexTransport.MultiplexEnabled()
}
func (h *Outbound) InterfaceUpdated(ctx context.Context) {
@@ -126,10 +130,20 @@ func (h *Outbound) InterfaceUpdated(ctx context.Context) {
}
}
func (h *Outbound) SetKeepIdleConnections(keep bool) {
transportKeeper, isTransportKeeper := h.transport.(adapter.IdleConnectionKeeper)
if isTransportKeeper {
transportKeeper.SetKeepIdleConnections(keep)
}
if h.multiplexDialer != nil {
h.multiplexDialer.SetKeepIdleConnections(keep)
}
}
func (h *Outbound) CloseIdleConnections() {
transportCloser, isTransportCloser := h.transport.(adapter.IdleConnectionCloser)
if isTransportCloser {
transportCloser.CloseIdleConnections()
transportKeeper, isTransportKeeper := h.transport.(adapter.IdleConnectionKeeper)
if isTransportKeeper {
transportKeeper.CloseIdleConnections()
}
if h.multiplexDialer != nil {
h.multiplexDialer.CloseIdleConnections()
+10 -1
View File
@@ -32,7 +32,8 @@ func RegisterOutbound(registry *outbound.Registry) {
var (
_ adapter.InterfaceUpdateListener = (*Outbound)(nil)
_ adapter.IdleConnectionCloser = (*Outbound)(nil)
_ adapter.IdleConnectionKeeper = (*Outbound)(nil)
_ adapter.OutboundWithMultiplex = (*Outbound)(nil)
)
type Outbound struct {
@@ -148,6 +149,14 @@ func (h *Outbound) InterfaceUpdated(ctx context.Context) {
_ = h.client.CloseWithError(E.New("network changed"))
}
func (h *Outbound) MultiplexEnabled() bool {
return true
}
func (h *Outbound) SetKeepIdleConnections(keep bool) {
h.client.SetKeepIdleConnections(keep)
}
func (h *Outbound) CloseIdleConnections() {
h.client.CloseIdleConnections()
}
+19 -5
View File
@@ -30,7 +30,7 @@ func RegisterOutbound(registry *outbound.Registry) {
var (
_ adapter.OutboundWithMultiplex = (*Outbound)(nil)
_ adapter.InterfaceUpdateListener = (*Outbound)(nil)
_ adapter.IdleConnectionCloser = (*Outbound)(nil)
_ adapter.IdleConnectionKeeper = (*Outbound)(nil)
)
type Outbound struct {
@@ -134,7 +134,11 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
}
func (h *Outbound) MultiplexEnabled() bool {
return h.multiplexDialer != nil
if h.multiplexDialer != nil {
return true
}
multiplexTransport, isMultiplexTransport := h.transport.(adapter.V2RayMultiplexClientTransport)
return isMultiplexTransport && multiplexTransport.MultiplexEnabled()
}
func (h *Outbound) InterfaceUpdated(ctx context.Context) {
@@ -146,10 +150,20 @@ func (h *Outbound) InterfaceUpdated(ctx context.Context) {
}
}
func (h *Outbound) SetKeepIdleConnections(keep bool) {
transportKeeper, isTransportKeeper := h.transport.(adapter.IdleConnectionKeeper)
if isTransportKeeper {
transportKeeper.SetKeepIdleConnections(keep)
}
if h.multiplexDialer != nil {
h.multiplexDialer.SetKeepIdleConnections(keep)
}
}
func (h *Outbound) CloseIdleConnections() {
transportCloser, isTransportCloser := h.transport.(adapter.IdleConnectionCloser)
if isTransportCloser {
transportCloser.CloseIdleConnections()
transportKeeper, isTransportKeeper := h.transport.(adapter.IdleConnectionKeeper)
if isTransportKeeper {
transportKeeper.CloseIdleConnections()
}
if h.multiplexDialer != nil {
h.multiplexDialer.CloseIdleConnections()
+19 -5
View File
@@ -30,7 +30,7 @@ func RegisterOutbound(registry *outbound.Registry) {
var (
_ adapter.OutboundWithMultiplex = (*Outbound)(nil)
_ adapter.InterfaceUpdateListener = (*Outbound)(nil)
_ adapter.IdleConnectionCloser = (*Outbound)(nil)
_ adapter.IdleConnectionKeeper = (*Outbound)(nil)
)
type Outbound struct {
@@ -112,7 +112,11 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
}
func (h *Outbound) MultiplexEnabled() bool {
return h.multiplexDialer != nil
if h.multiplexDialer != nil {
return true
}
multiplexTransport, isMultiplexTransport := h.transport.(adapter.V2RayMultiplexClientTransport)
return isMultiplexTransport && multiplexTransport.MultiplexEnabled()
}
func (h *Outbound) InterfaceUpdated(ctx context.Context) {
@@ -124,10 +128,20 @@ func (h *Outbound) InterfaceUpdated(ctx context.Context) {
}
}
func (h *Outbound) SetKeepIdleConnections(keep bool) {
transportKeeper, isTransportKeeper := h.transport.(adapter.IdleConnectionKeeper)
if isTransportKeeper {
transportKeeper.SetKeepIdleConnections(keep)
}
if h.multiplexDialer != nil {
h.multiplexDialer.SetKeepIdleConnections(keep)
}
}
func (h *Outbound) CloseIdleConnections() {
transportCloser, isTransportCloser := h.transport.(adapter.IdleConnectionCloser)
if isTransportCloser {
transportCloser.CloseIdleConnections()
transportKeeper, isTransportKeeper := h.transport.(adapter.IdleConnectionKeeper)
if isTransportKeeper {
transportKeeper.CloseIdleConnections()
}
if h.multiplexDialer != nil {
h.multiplexDialer.CloseIdleConnections()