mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-05-08 14:13:22 +00:00
Hysteria transport: Add congestion config (""/"reno"/"bbr"/"brutal"/"force-brutal") (#5549)
Closes https://github.com/XTLS/Xray-core/issues/5546
This commit is contained in:
@@ -391,11 +391,12 @@ type UdpHop struct {
|
||||
}
|
||||
|
||||
type HysteriaConfig struct {
|
||||
Version int32 `json:"version"`
|
||||
Auth string `json:"auth"`
|
||||
Up Bandwidth `json:"up"`
|
||||
Down Bandwidth `json:"down"`
|
||||
UdpHop UdpHop `json:"udphop"`
|
||||
Version int32 `json:"version"`
|
||||
Auth string `json:"auth"`
|
||||
Congestion string `json:"congestion"`
|
||||
Up Bandwidth `json:"up"`
|
||||
Down Bandwidth `json:"down"`
|
||||
UdpHop UdpHop `json:"udphop"`
|
||||
|
||||
InitStreamReceiveWindow uint64 `json:"initStreamReceiveWindow"`
|
||||
MaxStreamReceiveWindow uint64 `json:"maxStreamReceiveWindow"`
|
||||
@@ -410,6 +411,7 @@ func (c *HysteriaConfig) Build() (proto.Message, error) {
|
||||
if c.Version != 2 {
|
||||
return nil, errors.New("version != 2")
|
||||
}
|
||||
|
||||
up, err := c.Up.Bps()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -418,6 +420,12 @@ func (c *HysteriaConfig) Build() (proto.Message, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.Congestion = strings.ToLower(c.Congestion)
|
||||
if c.Congestion == "force-brutal" && up == 0 {
|
||||
return nil, errors.New("force-brutal require up")
|
||||
}
|
||||
|
||||
var hop *PortList
|
||||
if err := json.Unmarshal(c.UdpHop.PortList, &hop); err != nil {
|
||||
hop = &PortList{}
|
||||
@@ -455,6 +463,7 @@ func (c *HysteriaConfig) Build() (proto.Message, error) {
|
||||
config := &hysteria.Config{}
|
||||
config.Version = c.Version
|
||||
config.Auth = c.Auth
|
||||
config.Congestion = c.Congestion
|
||||
config.Up = up
|
||||
config.Down = down
|
||||
config.Ports = hop.Build().Ports()
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/policy"
|
||||
hyCtx "github.com/xtls/xray-core/proxy/hysteria/ctx"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
"github.com/xtls/xray-core/transport/internet/hysteria"
|
||||
@@ -55,6 +56,9 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
||||
ob.CanSpliceCopy = 3
|
||||
target := ob.Target
|
||||
|
||||
if target.Network == net.Network_UDP {
|
||||
hyCtx.ContextWithRequireDatagram(ctx)
|
||||
}
|
||||
conn, err := dialer.Dial(ctx, c.server.Destination)
|
||||
if err != nil {
|
||||
return errors.New("failed to find an available destination").AtWarning().Base(err)
|
||||
|
||||
20
proxy/hysteria/ctx/ctx.go
Normal file
20
proxy/hysteria/ctx/ctx.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package ctx
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type key int
|
||||
|
||||
const (
|
||||
requireDatagram key = iota
|
||||
)
|
||||
|
||||
func ContextWithRequireDatagram(ctx context.Context) context.Context {
|
||||
return context.WithValue(ctx, requireDatagram, struct{}{})
|
||||
}
|
||||
|
||||
func RequireDatagramFromContext(ctx context.Context) bool {
|
||||
_, ok := ctx.Value(requireDatagram).(struct{})
|
||||
return ok
|
||||
}
|
||||
@@ -25,17 +25,18 @@ type Config struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Version int32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
|
||||
Auth string `protobuf:"bytes,2,opt,name=auth,proto3" json:"auth,omitempty"`
|
||||
Up uint64 `protobuf:"varint,3,opt,name=up,proto3" json:"up,omitempty"`
|
||||
Down uint64 `protobuf:"varint,4,opt,name=down,proto3" json:"down,omitempty"`
|
||||
Ports []uint32 `protobuf:"varint,5,rep,packed,name=ports,proto3" json:"ports,omitempty"`
|
||||
Interval int64 `protobuf:"varint,6,opt,name=interval,proto3" json:"interval,omitempty"`
|
||||
InitStreamReceiveWindow uint64 `protobuf:"varint,7,opt,name=init_stream_receive_window,json=initStreamReceiveWindow,proto3" json:"init_stream_receive_window,omitempty"`
|
||||
MaxStreamReceiveWindow uint64 `protobuf:"varint,8,opt,name=max_stream_receive_window,json=maxStreamReceiveWindow,proto3" json:"max_stream_receive_window,omitempty"`
|
||||
InitConnReceiveWindow uint64 `protobuf:"varint,9,opt,name=init_conn_receive_window,json=initConnReceiveWindow,proto3" json:"init_conn_receive_window,omitempty"`
|
||||
MaxConnReceiveWindow uint64 `protobuf:"varint,10,opt,name=max_conn_receive_window,json=maxConnReceiveWindow,proto3" json:"max_conn_receive_window,omitempty"`
|
||||
MaxIdleTimeout int64 `protobuf:"varint,11,opt,name=max_idle_timeout,json=maxIdleTimeout,proto3" json:"max_idle_timeout,omitempty"`
|
||||
KeepAlivePeriod int64 `protobuf:"varint,12,opt,name=keep_alive_period,json=keepAlivePeriod,proto3" json:"keep_alive_period,omitempty"`
|
||||
DisablePathMtuDiscovery bool `protobuf:"varint,13,opt,name=disable_path_mtu_discovery,json=disablePathMtuDiscovery,proto3" json:"disable_path_mtu_discovery,omitempty"`
|
||||
Congestion string `protobuf:"bytes,3,opt,name=congestion,proto3" json:"congestion,omitempty"`
|
||||
Up uint64 `protobuf:"varint,4,opt,name=up,proto3" json:"up,omitempty"`
|
||||
Down uint64 `protobuf:"varint,5,opt,name=down,proto3" json:"down,omitempty"`
|
||||
Ports []uint32 `protobuf:"varint,6,rep,packed,name=ports,proto3" json:"ports,omitempty"`
|
||||
Interval int64 `protobuf:"varint,7,opt,name=interval,proto3" json:"interval,omitempty"`
|
||||
InitStreamReceiveWindow uint64 `protobuf:"varint,8,opt,name=init_stream_receive_window,json=initStreamReceiveWindow,proto3" json:"init_stream_receive_window,omitempty"`
|
||||
MaxStreamReceiveWindow uint64 `protobuf:"varint,9,opt,name=max_stream_receive_window,json=maxStreamReceiveWindow,proto3" json:"max_stream_receive_window,omitempty"`
|
||||
InitConnReceiveWindow uint64 `protobuf:"varint,10,opt,name=init_conn_receive_window,json=initConnReceiveWindow,proto3" json:"init_conn_receive_window,omitempty"`
|
||||
MaxConnReceiveWindow uint64 `protobuf:"varint,11,opt,name=max_conn_receive_window,json=maxConnReceiveWindow,proto3" json:"max_conn_receive_window,omitempty"`
|
||||
MaxIdleTimeout int64 `protobuf:"varint,12,opt,name=max_idle_timeout,json=maxIdleTimeout,proto3" json:"max_idle_timeout,omitempty"`
|
||||
KeepAlivePeriod int64 `protobuf:"varint,13,opt,name=keep_alive_period,json=keepAlivePeriod,proto3" json:"keep_alive_period,omitempty"`
|
||||
DisablePathMtuDiscovery bool `protobuf:"varint,14,opt,name=disable_path_mtu_discovery,json=disablePathMtuDiscovery,proto3" json:"disable_path_mtu_discovery,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@@ -84,6 +85,13 @@ func (x *Config) GetAuth() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Config) GetCongestion() string {
|
||||
if x != nil {
|
||||
return x.Congestion
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Config) GetUp() uint64 {
|
||||
if x != nil {
|
||||
return x.Up
|
||||
@@ -165,22 +173,25 @@ var File_transport_internet_hysteria_config_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_transport_internet_hysteria_config_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"(transport/internet/hysteria/config.proto\x12 xray.transport.internet.hysteria\"\x87\x04\n" +
|
||||
"(transport/internet/hysteria/config.proto\x12 xray.transport.internet.hysteria\"\xa7\x04\n" +
|
||||
"\x06Config\x12\x18\n" +
|
||||
"\aversion\x18\x01 \x01(\x05R\aversion\x12\x12\n" +
|
||||
"\x04auth\x18\x02 \x01(\tR\x04auth\x12\x0e\n" +
|
||||
"\x02up\x18\x03 \x01(\x04R\x02up\x12\x12\n" +
|
||||
"\x04down\x18\x04 \x01(\x04R\x04down\x12\x14\n" +
|
||||
"\x05ports\x18\x05 \x03(\rR\x05ports\x12\x1a\n" +
|
||||
"\binterval\x18\x06 \x01(\x03R\binterval\x12;\n" +
|
||||
"\x1ainit_stream_receive_window\x18\a \x01(\x04R\x17initStreamReceiveWindow\x129\n" +
|
||||
"\x19max_stream_receive_window\x18\b \x01(\x04R\x16maxStreamReceiveWindow\x127\n" +
|
||||
"\x18init_conn_receive_window\x18\t \x01(\x04R\x15initConnReceiveWindow\x125\n" +
|
||||
"\x17max_conn_receive_window\x18\n" +
|
||||
" \x01(\x04R\x14maxConnReceiveWindow\x12(\n" +
|
||||
"\x10max_idle_timeout\x18\v \x01(\x03R\x0emaxIdleTimeout\x12*\n" +
|
||||
"\x11keep_alive_period\x18\f \x01(\x03R\x0fkeepAlivePeriod\x12;\n" +
|
||||
"\x1adisable_path_mtu_discovery\x18\r \x01(\bR\x17disablePathMtuDiscoveryB\x82\x01\n" +
|
||||
"\x04auth\x18\x02 \x01(\tR\x04auth\x12\x1e\n" +
|
||||
"\n" +
|
||||
"congestion\x18\x03 \x01(\tR\n" +
|
||||
"congestion\x12\x0e\n" +
|
||||
"\x02up\x18\x04 \x01(\x04R\x02up\x12\x12\n" +
|
||||
"\x04down\x18\x05 \x01(\x04R\x04down\x12\x14\n" +
|
||||
"\x05ports\x18\x06 \x03(\rR\x05ports\x12\x1a\n" +
|
||||
"\binterval\x18\a \x01(\x03R\binterval\x12;\n" +
|
||||
"\x1ainit_stream_receive_window\x18\b \x01(\x04R\x17initStreamReceiveWindow\x129\n" +
|
||||
"\x19max_stream_receive_window\x18\t \x01(\x04R\x16maxStreamReceiveWindow\x127\n" +
|
||||
"\x18init_conn_receive_window\x18\n" +
|
||||
" \x01(\x04R\x15initConnReceiveWindow\x125\n" +
|
||||
"\x17max_conn_receive_window\x18\v \x01(\x04R\x14maxConnReceiveWindow\x12(\n" +
|
||||
"\x10max_idle_timeout\x18\f \x01(\x03R\x0emaxIdleTimeout\x12*\n" +
|
||||
"\x11keep_alive_period\x18\r \x01(\x03R\x0fkeepAlivePeriod\x12;\n" +
|
||||
"\x1adisable_path_mtu_discovery\x18\x0e \x01(\bR\x17disablePathMtuDiscoveryB\x82\x01\n" +
|
||||
"$com.xray.transport.internet.hysteriaP\x01Z5github.com/xtls/xray-core/transport/internet/hysteria\xaa\x02 Xray.Transport.Internet.Hysteriab\x06proto3"
|
||||
|
||||
var (
|
||||
|
||||
@@ -9,17 +9,18 @@ option java_multiple_files = true;
|
||||
message Config {
|
||||
int32 version = 1;
|
||||
string auth = 2;
|
||||
uint64 up = 3;
|
||||
uint64 down = 4;
|
||||
repeated uint32 ports = 5;
|
||||
int64 interval = 6;
|
||||
string congestion = 3;
|
||||
uint64 up = 4;
|
||||
uint64 down = 5;
|
||||
repeated uint32 ports = 6;
|
||||
int64 interval = 7;
|
||||
|
||||
uint64 init_stream_receive_window = 7;
|
||||
uint64 max_stream_receive_window = 8;
|
||||
uint64 init_conn_receive_window = 9;
|
||||
uint64 max_conn_receive_window = 10;
|
||||
int64 max_idle_timeout = 11;
|
||||
int64 keep_alive_period = 12;
|
||||
bool disable_path_mtu_discovery = 13;
|
||||
uint64 init_stream_receive_window = 8;
|
||||
uint64 max_stream_receive_window = 9;
|
||||
uint64 init_conn_receive_window = 10;
|
||||
uint64 max_conn_receive_window = 11;
|
||||
int64 max_idle_timeout = 12;
|
||||
int64 keep_alive_period = 13;
|
||||
bool disable_path_mtu_discovery = 14;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,9 @@ func (i *InterUdpConn) Read(p []byte) (int, error) {
|
||||
return 0, io.EOF
|
||||
}
|
||||
n := copy(p, b)
|
||||
if n != len(b) {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ import (
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
hyCtx "github.com/xtls/xray-core/proxy/hysteria/ctx"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
"github.com/xtls/xray-core/transport/internet/finalmask"
|
||||
"github.com/xtls/xray-core/transport/internet/hysteria/congestion"
|
||||
@@ -115,8 +115,8 @@ type client struct {
|
||||
conn *quic.Conn
|
||||
config *Config
|
||||
tlsConfig *go_tls.Config
|
||||
udpmaskManager *finalmask.UdpmaskManager
|
||||
socketConfig *internet.SocketConfig
|
||||
udpmaskManager *finalmask.UdpmaskManager
|
||||
udpSM *udpSessionManager
|
||||
mutex sync.Mutex
|
||||
}
|
||||
@@ -243,10 +243,25 @@ func (c *client) dial() error {
|
||||
serverAuto := resp.Header.Get(CommonHeaderCCRX)
|
||||
serverDown, _ := strconv.ParseUint(serverAuto, 10, 64)
|
||||
|
||||
if serverAuto == "auto" || c.config.Up == 0 || serverDown == 0 {
|
||||
switch c.config.Congestion {
|
||||
case "reno":
|
||||
errors.LogDebug(c.ctx, "congestion reno")
|
||||
case "bbr":
|
||||
errors.LogDebug(c.ctx, "congestion bbr")
|
||||
congestion.UseBBR(quicConn)
|
||||
} else {
|
||||
congestion.UseBrutal(quicConn, min(c.config.Up, serverDown))
|
||||
case "brutal", "":
|
||||
if serverAuto == "auto" || c.config.Up == 0 || serverDown == 0 {
|
||||
errors.LogDebug(c.ctx, "congestion bbr")
|
||||
congestion.UseBBR(quicConn)
|
||||
} else {
|
||||
errors.LogDebug(c.ctx, "congestion brutal bytes per second ", min(c.config.Up, serverDown))
|
||||
congestion.UseBrutal(quicConn, min(c.config.Up, serverDown))
|
||||
}
|
||||
case "force-brutal":
|
||||
errors.LogDebug(c.ctx, "congestion brutal bytes per second ", c.config.Up)
|
||||
congestion.UseBrutal(quicConn, c.config.Up)
|
||||
default:
|
||||
errors.LogDebug(c.ctx, "congestion reno")
|
||||
}
|
||||
|
||||
c.pktConn = pktConn
|
||||
@@ -363,6 +378,7 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
|
||||
return nil, errors.New("tls config is nil")
|
||||
}
|
||||
|
||||
requireDatagram := hyCtx.RequireDatagramFromContext(ctx)
|
||||
addr := dest.NetAddr()
|
||||
config := streamSettings.ProtocolSettings.(*Config)
|
||||
|
||||
@@ -375,18 +391,15 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
|
||||
dest: dest,
|
||||
config: config,
|
||||
tlsConfig: tlsConfig.GetTLSConfig(),
|
||||
udpmaskManager: streamSettings.UdpmaskManager,
|
||||
socketConfig: streamSettings.SocketSettings,
|
||||
udpmaskManager: streamSettings.UdpmaskManager,
|
||||
}
|
||||
manger.m[addr] = c
|
||||
}
|
||||
c.setCtx(ctx)
|
||||
manger.mutex.Unlock()
|
||||
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
targetUdp := len(outbounds) > 0 && outbounds[len(outbounds)-1].Target.Network == net.Network_UDP
|
||||
|
||||
if targetUdp {
|
||||
if requireDatagram {
|
||||
return c.udp()
|
||||
}
|
||||
return c.tcp()
|
||||
|
||||
Reference in New Issue
Block a user