diff --git a/common/mux/client.go b/common/mux/client.go index 28380331..d117f86b 100644 --- a/common/mux/client.go +++ b/common/mux/client.go @@ -170,7 +170,7 @@ func (f *DialingWorkerFactory) Create() (*ClientWorker, error) { type ClientStrategy struct { MaxConcurrency uint32 - MaxConnection uint32 + MaxReuseTimes uint32 } type ClientWorker struct { @@ -288,7 +288,7 @@ func fetchInput(ctx context.Context, s *Session, output buf.Writer) { func (m *ClientWorker) IsClosing() bool { sm := m.sessionManager - if m.strategy.MaxConnection > 0 && sm.Count() >= int(m.strategy.MaxConnection) { + if m.strategy.MaxReuseTimes > 0 && sm.Count() >= int(m.strategy.MaxReuseTimes) { return true } return false diff --git a/common/mux/client_test.go b/common/mux/client_test.go index 9626e2a2..d0238e96 100644 --- a/common/mux/client_test.go +++ b/common/mux/client_test.go @@ -58,7 +58,7 @@ func TestClientWorkerClose(t *testing.T) { Writer: w1, }, mux.ClientStrategy{ MaxConcurrency: 4, - MaxConnection: 4, + MaxReuseTimes: 4, }) common.Must(err) @@ -68,7 +68,7 @@ func TestClientWorkerClose(t *testing.T) { Writer: w2, }, mux.ClientStrategy{ MaxConcurrency: 4, - MaxConnection: 4, + MaxReuseTimes: 4, }) common.Must(err) diff --git a/common/mux/session.go b/common/mux/session.go index 66b9674c..266b8de8 100644 --- a/common/mux/session.go +++ b/common/mux/session.go @@ -56,11 +56,12 @@ func (m *SessionManager) Allocate(Strategy *ClientStrategy) *Session { defer m.Unlock() MaxConcurrency := int(Strategy.MaxConcurrency) - MaxConnection := uint16(Strategy.MaxConnection) + MaxReuseTimes := uint16(Strategy.MaxReuseTimes) - if m.closed || (MaxConcurrency > 0 && len(m.sessions) >= MaxConcurrency) || (MaxConnection > 0 && m.count >= MaxConnection) { + if m.closed || (MaxConcurrency > 0 && len(m.sessions) >= MaxConcurrency) || (MaxReuseTimes > 0 && m.count >= MaxReuseTimes) { return nil } + errors.LogInfo(context.Background(), "Allocated mux.cool session id ", m.count, "/", MaxReuseTimes) m.count++ s := &Session{ diff --git a/transport/internet/brutal/brutal.go b/transport/internet/brutal/brutal.go new file mode 100644 index 00000000..82a4def4 --- /dev/null +++ b/transport/internet/brutal/brutal.go @@ -0,0 +1,53 @@ +//go:build linux + +package brutal + +import ( + "os" + "unsafe" + + "github.com/xtls/xray-core/common/net" + "golang.org/x/sys/unix" +) + +//go:linkname setsockopt syscall.setsockopt +func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) + +const ( + TCP_BRUTAL_PARAMS = 23301 +) + +type TCPBrutalParams struct { + Rate uint64 + CwndGain uint32 +} + +func setBrutalFD(fd uintptr, sendBPS uint64) error { + err := unix.SetsockoptString(int(fd), unix.IPPROTO_TCP, unix.TCP_CONGESTION, "brutal") + if err != nil { + return err + } + params := TCPBrutalParams{ + Rate: sendBPS, + CwndGain: 20, // hysteria2 default + } + err = setsockopt(int(fd), unix.IPPROTO_TCP, TCP_BRUTAL_PARAMS, unsafe.Pointer(¶ms), unsafe.Sizeof(params)) + if err != nil { + return os.NewSyscallError("setsockopt IPPROTO_TCP TCP_BRUTAL_PARAMS", err) + } + return nil +} + +func SetBrutal(conn *net.TCPConn, sendBPS uint64) error { + syscallConn, err := conn.SyscallConn() + if err != nil { + return err + } + syscallConn.Control(func(fd uintptr) { + err = setBrutalFD(fd, sendBPS) + }) + if err != nil { + return err + } + return nil +} diff --git a/transport/internet/brutal/brutal_others.go b/transport/internet/brutal/brutal_others.go new file mode 100644 index 00000000..7245b536 --- /dev/null +++ b/transport/internet/brutal/brutal_others.go @@ -0,0 +1,12 @@ +//go:build !linux + +package brutal + +import ( + "github.com/xtls/xray-core/common/errors" + "github.com/xtls/xray-core/common/net" +) + +func SetBrutal(conn *net.TCPConn, sendBPS uint64) error { + return errors.New("brutal not available on this platform") +}