mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-12-18 05:04:36 +03:00
Some checks are pending
Build and Release / build (arm, 7, linux) (push) Blocked by required conditions
Build and Release / build (arm, 7, openbsd) (push) Blocked by required conditions
Build and Release / build (arm, 7, windows) (push) Blocked by required conditions
Build and Release / build (arm64, android) (push) Blocked by required conditions
Build and Release / build (arm64, darwin) (push) Blocked by required conditions
Build and Release / build (arm64, freebsd) (push) Blocked by required conditions
Build and Release / build (arm64, linux) (push) Blocked by required conditions
Build and Release / build (arm64, openbsd) (push) Blocked by required conditions
Build and Release / build (arm64, windows) (push) Blocked by required conditions
Build and Release / build (loong64, linux) (push) Blocked by required conditions
Build and Release / build (mips, linux) (push) Blocked by required conditions
Build and Release / build (mips64, linux) (push) Blocked by required conditions
Build and Release / build (mips64le, linux) (push) Blocked by required conditions
Build and Release / build (mipsle, linux) (push) Blocked by required conditions
Build and Release / build (ppc64, linux) (push) Blocked by required conditions
Build and Release / build (ppc64le, linux) (push) Blocked by required conditions
Build and Release / build (riscv64, linux) (push) Blocked by required conditions
Build and Release / build (s390x, linux) (push) Blocked by required conditions
Test / test (macos-latest) (push) Waiting to run
Test / test (ubuntu-latest) (push) Waiting to run
Test / test (windows-latest) (push) Waiting to run
Build docker image / build-image (push) Waiting to run
Build and Release / prepare (push) Waiting to run
Build and Release / build (386, freebsd, , ) (push) Blocked by required conditions
Build and Release / build (386, linux, , ) (push) Blocked by required conditions
Build and Release / build (386, openbsd, , ) (push) Blocked by required conditions
Build and Release / build (386, windows, , ) (push) Blocked by required conditions
Build and Release / build (386, windows, 1.21.4, win7-32) (push) Blocked by required conditions
Build and Release / build (amd64, darwin, , ) (push) Blocked by required conditions
Build and Release / build (amd64, freebsd, , ) (push) Blocked by required conditions
Build and Release / build (amd64, linux, , ) (push) Blocked by required conditions
Build and Release / build (amd64, openbsd, , ) (push) Blocked by required conditions
Build and Release / build (amd64, windows, , ) (push) Blocked by required conditions
Build and Release / build (amd64, windows, 1.21.4, win7-64) (push) Blocked by required conditions
Build and Release / build (arm, 5, linux) (push) Blocked by required conditions
Build and Release / build (arm, 6, linux) (push) Blocked by required conditions
Build and Release / build (arm, 7, freebsd) (push) Blocked by required conditions
Fixes https://github.com/XTLS/Xray-core/discussions/4113#discussioncomment-11492833
115 lines
3.2 KiB
Go
115 lines
3.2 KiB
Go
package splithttp
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"math"
|
|
"math/big"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"github.com/xtls/xray-core/common/errors"
|
|
)
|
|
|
|
type XmuxConn interface {
|
|
IsClosed() bool
|
|
}
|
|
|
|
type XmuxClient struct {
|
|
XmuxConn XmuxConn
|
|
OpenUsage atomic.Int32
|
|
leftUsage int32
|
|
expirationTime time.Time
|
|
LeftRequests atomic.Int32
|
|
}
|
|
|
|
type XmuxManager struct {
|
|
xmuxConfig XmuxConfig
|
|
concurrency int32
|
|
connections int32
|
|
newConnFunc func() XmuxConn
|
|
xmuxClients []*XmuxClient
|
|
}
|
|
|
|
func NewXmuxManager(xmuxConfig XmuxConfig, newConnFunc func() XmuxConn) *XmuxManager {
|
|
return &XmuxManager{
|
|
xmuxConfig: xmuxConfig,
|
|
concurrency: xmuxConfig.GetNormalizedMaxConcurrency().rand(),
|
|
connections: xmuxConfig.GetNormalizedMaxConnections().rand(),
|
|
newConnFunc: newConnFunc,
|
|
xmuxClients: make([]*XmuxClient, 0),
|
|
}
|
|
}
|
|
|
|
func (m *XmuxManager) newXmuxClient() *XmuxClient {
|
|
xmuxClient := &XmuxClient{
|
|
XmuxConn: m.newConnFunc(),
|
|
leftUsage: -1,
|
|
expirationTime: time.UnixMilli(0),
|
|
}
|
|
if x := m.xmuxConfig.GetNormalizedCMaxReuseTimes().rand(); x > 0 {
|
|
xmuxClient.leftUsage = x - 1
|
|
}
|
|
if x := m.xmuxConfig.GetNormalizedCMaxLifetimeMs().rand(); x > 0 {
|
|
xmuxClient.expirationTime = time.Now().Add(time.Duration(x) * time.Millisecond)
|
|
}
|
|
xmuxClient.LeftRequests.Store(math.MaxInt32)
|
|
if x := m.xmuxConfig.GetNormalizedCMaxRequestTimes().rand(); x > 0 {
|
|
xmuxClient.LeftRequests.Store(x)
|
|
}
|
|
m.xmuxClients = append(m.xmuxClients, xmuxClient)
|
|
return xmuxClient
|
|
}
|
|
|
|
func (m *XmuxManager) GetXmuxClient(ctx context.Context) *XmuxClient { // when locking
|
|
for i := 0; i < len(m.xmuxClients); {
|
|
xmuxClient := m.xmuxClients[i]
|
|
if xmuxClient.XmuxConn.IsClosed() ||
|
|
xmuxClient.leftUsage == 0 ||
|
|
(xmuxClient.expirationTime != time.UnixMilli(0) && time.Now().After(xmuxClient.expirationTime)) ||
|
|
xmuxClient.LeftRequests.Load() <= 0 {
|
|
errors.LogDebug(ctx, "XMUX: removing xmuxClient, IsClosed() = ", xmuxClient.XmuxConn.IsClosed(),
|
|
", OpenUsage = ", xmuxClient.OpenUsage.Load(),
|
|
", leftUsage = ", xmuxClient.leftUsage,
|
|
", expirationTime = ", xmuxClient.expirationTime,
|
|
", LeftRequests = ", xmuxClient.LeftRequests.Load())
|
|
m.xmuxClients = append(m.xmuxClients[:i], m.xmuxClients[i+1:]...)
|
|
} else {
|
|
i++
|
|
}
|
|
}
|
|
|
|
if len(m.xmuxClients) == 0 {
|
|
errors.LogDebug(ctx, "XMUX: creating xmuxClient because xmuxClients is empty")
|
|
return m.newXmuxClient()
|
|
}
|
|
|
|
if m.connections > 0 && len(m.xmuxClients) < int(m.connections) {
|
|
errors.LogDebug(ctx, "XMUX: creating xmuxClient because maxConnections was not hit, xmuxClients = ", len(m.xmuxClients))
|
|
return m.newXmuxClient()
|
|
}
|
|
|
|
xmuxClients := make([]*XmuxClient, 0)
|
|
if m.concurrency > 0 {
|
|
for _, xmuxClient := range m.xmuxClients {
|
|
if xmuxClient.OpenUsage.Load() < m.concurrency {
|
|
xmuxClients = append(xmuxClients, xmuxClient)
|
|
}
|
|
}
|
|
} else {
|
|
xmuxClients = m.xmuxClients
|
|
}
|
|
|
|
if len(xmuxClients) == 0 {
|
|
errors.LogDebug(ctx, "XMUX: creating xmuxClient because maxConcurrency was hit, xmuxClients = ", len(m.xmuxClients))
|
|
return m.newXmuxClient()
|
|
}
|
|
|
|
i, _ := rand.Int(rand.Reader, big.NewInt(int64(len(xmuxClients))))
|
|
xmuxClient := xmuxClients[i.Int64()]
|
|
if xmuxClient.leftUsage > 0 {
|
|
xmuxClient.leftUsage -= 1
|
|
}
|
|
return xmuxClient
|
|
}
|