diff --git a/infra/conf/transport_internet.go b/infra/conf/transport_internet.go index b1c589f1..f0dd08ff 100644 --- a/infra/conf/transport_internet.go +++ b/infra/conf/transport_internet.go @@ -14,6 +14,7 @@ import ( "syscall" "time" + "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/platform/filesystem" @@ -54,64 +55,57 @@ var ( ) type KCPConfig struct { - Mtu *uint32 `json:"mtu"` - Tti *uint32 `json:"tti"` - UpCap *uint32 `json:"uplinkCapacity"` - DownCap *uint32 `json:"downlinkCapacity"` - Congestion *bool `json:"congestion"` - ReadBufferSize *uint32 `json:"readBufferSize"` - WriteBufferSize *uint32 `json:"writeBufferSize"` - HeaderConfig json.RawMessage `json:"header"` - Seed *string `json:"seed"` + Mtu *uint32 `json:"mtu"` + Tti *uint32 `json:"tti"` + UpCap *uint32 `json:"uplinkCapacity"` + DownCap *uint32 `json:"downlinkCapacity"` + CwndMultiplier *uint32 `json:"cwndMultiplier"` + MaxSendingWindow *uint32 `json:"maxSendingWindow"` + + HeaderConfig json.RawMessage `json:"header"` + Seed *string `json:"seed"` } // Build implements Buildable. func (c *KCPConfig) Build() (proto.Message, error) { - config := new(kcp.Config) - - if c.Mtu != nil { - mtu := *c.Mtu - // if mtu < 576 || mtu > 1460 { - // return nil, errors.New("invalid mKCP MTU size: ", mtu).AtError() - // } - config.Mtu = &kcp.MTU{Value: mtu} - } - if c.Tti != nil { - tti := *c.Tti - if tti < 10 || tti > 5000 { - return nil, errors.New("invalid mKCP TTI: ", tti).AtError() - } - config.Tti = &kcp.TTI{Value: tti} - } - if c.UpCap != nil { - config.UplinkCapacity = &kcp.UplinkCapacity{Value: *c.UpCap} - } - if c.DownCap != nil { - config.DownlinkCapacity = &kcp.DownlinkCapacity{Value: *c.DownCap} - } - if c.Congestion != nil { - config.Congestion = *c.Congestion - } - if c.ReadBufferSize != nil { - size := *c.ReadBufferSize - if size > 0 { - config.ReadBuffer = &kcp.ReadBuffer{Size: size * 1024 * 1024} - } else { - config.ReadBuffer = &kcp.ReadBuffer{Size: 512 * 1024} - } - } - if c.WriteBufferSize != nil { - size := *c.WriteBufferSize - if size > 0 { - config.WriteBuffer = &kcp.WriteBuffer{Size: size * 1024 * 1024} - } else { - config.WriteBuffer = &kcp.WriteBuffer{Size: 512 * 1024} - } - } if c.HeaderConfig != nil || c.Seed != nil { return nil, errors.PrintRemovedFeatureError("mkcp header & seed", "finalmask/udp header-* & mkcp-original & mkcp-aes128gcm") } + config := common.Must2(internet.CreateTransportConfig(kcp.ProtocolName)).(*kcp.Config) + + if c.Mtu != nil { + config.Mtu = *c.Mtu + } + if c.Tti != nil { + config.Tti = *c.Tti + } + if c.UpCap != nil { + config.UplinkCapacity = *c.UpCap + } + if c.DownCap != nil { + config.DownlinkCapacity = *c.DownCap + } + if c.CwndMultiplier != nil { + config.CwndMultiplier = *c.CwndMultiplier + } + if c.MaxSendingWindow != nil { + config.MaxSendingWindow = *c.MaxSendingWindow + } + + if config.Mtu < 21 { + return nil, errors.New("Mtu must be at least 21").AtError() + } + if config.Tti < 10 || config.Tti > 1000 { + return nil, errors.New("invalid mKCP TTI: ", c.Tti).AtError() + } + if config.CwndMultiplier < 1 { + return nil, errors.New("CwndMultiplier must be at least 1").AtError() + } + if config.GetSendingBufferSize() == 0 { + return nil, errors.New("MaxSendingWindow must be >= Mtu").AtError() + } + return config, nil } diff --git a/testing/scenarios/vmess_test.go b/testing/scenarios/vmess_test.go index 402cf940..64754f2b 100644 --- a/testing/scenarios/vmess_test.go +++ b/testing/scenarios/vmess_test.go @@ -22,7 +22,6 @@ import ( "github.com/xtls/xray-core/testing/servers/tcp" "github.com/xtls/xray-core/testing/servers/udp" "github.com/xtls/xray-core/transport/internet" - "github.com/xtls/xray-core/transport/internet/kcp" "golang.org/x/sync/errgroup" ) @@ -94,9 +93,9 @@ func TestVMessGCM(t *testing.T) { Receiver: &protocol.ServerEndpoint{ Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort), - User: &protocol.User{ + User: &protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{ - Id: userID.String(), + Id: userID.String(), SecuritySettings: &protocol.SecurityConfig{ Type: protocol.SecurityType_AES128_GCM, }, @@ -192,9 +191,9 @@ func TestVMessGCMReadv(t *testing.T) { Receiver: &protocol.ServerEndpoint{ Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort), - User: &protocol.User{ + User: &protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{ - Id: userID.String(), + Id: userID.String(), SecuritySettings: &protocol.SecurityConfig{ Type: protocol.SecurityType_AES128_GCM, }, @@ -293,9 +292,9 @@ func TestVMessGCMUDP(t *testing.T) { Receiver: &protocol.ServerEndpoint{ Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort), - User: &protocol.User{ + User: &protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{ - Id: userID.String(), + Id: userID.String(), SecuritySettings: &protocol.SecurityConfig{ Type: protocol.SecurityType_AES128_GCM, }, @@ -388,9 +387,9 @@ func TestVMessChacha20(t *testing.T) { Receiver: &protocol.ServerEndpoint{ Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort), - User: &protocol.User{ + User: &protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{ - Id: userID.String(), + Id: userID.String(), SecuritySettings: &protocol.SecurityConfig{ Type: protocol.SecurityType_CHACHA20_POLY1305, }, @@ -484,7 +483,7 @@ func TestVMessNone(t *testing.T) { Receiver: &protocol.ServerEndpoint{ Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort), - User: &protocol.User{ + User: &protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{ Id: userID.String(), SecuritySettings: &protocol.SecurityConfig{ @@ -638,25 +637,6 @@ func TestVMessKCPLarge(t *testing.T) { Listen: net.NewIPOrDomain(net.LocalHostIP), StreamSettings: &internet.StreamConfig{ ProtocolName: "mkcp", - TransportSettings: []*internet.TransportConfig{ - { - ProtocolName: "mkcp", - Settings: serial.ToTypedMessage(&kcp.Config{ - ReadBuffer: &kcp.ReadBuffer{ - Size: 512 * 1024, - }, - WriteBuffer: &kcp.WriteBuffer{ - Size: 512 * 1024, - }, - UplinkCapacity: &kcp.UplinkCapacity{ - Value: 20, - }, - DownlinkCapacity: &kcp.DownlinkCapacity{ - Value: 20, - }, - }), - }, - }, }, }), ProxySettings: serial.ToTypedMessage(&inbound.Config{ @@ -704,7 +684,7 @@ func TestVMessKCPLarge(t *testing.T) { Receiver: &protocol.ServerEndpoint{ Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort), - User: &protocol.User{ + User: &protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{ Id: userID.String(), SecuritySettings: &protocol.SecurityConfig{ @@ -717,25 +697,6 @@ func TestVMessKCPLarge(t *testing.T) { SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{ StreamSettings: &internet.StreamConfig{ ProtocolName: "mkcp", - TransportSettings: []*internet.TransportConfig{ - { - ProtocolName: "mkcp", - Settings: serial.ToTypedMessage(&kcp.Config{ - ReadBuffer: &kcp.ReadBuffer{ - Size: 512 * 1024, - }, - WriteBuffer: &kcp.WriteBuffer{ - Size: 512 * 1024, - }, - UplinkCapacity: &kcp.UplinkCapacity{ - Value: 20, - }, - DownlinkCapacity: &kcp.DownlinkCapacity{ - Value: 20, - }, - }), - }, - }, }, }), }, @@ -833,7 +794,7 @@ func TestVMessGCMMux(t *testing.T) { Receiver: &protocol.ServerEndpoint{ Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort), - User: &protocol.User{ + User: &protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{ Id: userID.String(), SecuritySettings: &protocol.SecurityConfig{ @@ -956,7 +917,7 @@ func TestVMessGCMMuxUDP(t *testing.T) { Receiver: &protocol.ServerEndpoint{ Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort), - User: &protocol.User{ + User: &protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{ Id: userID.String(), SecuritySettings: &protocol.SecurityConfig{ @@ -1059,7 +1020,7 @@ func TestVMessZero(t *testing.T) { Receiver: &protocol.ServerEndpoint{ Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort), - User: &protocol.User{ + User: &protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{ Id: userID.String(), SecuritySettings: &protocol.SecurityConfig{ @@ -1154,7 +1115,7 @@ func TestVMessGCMLengthAuth(t *testing.T) { Receiver: &protocol.ServerEndpoint{ Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort), - User: &protocol.User{ + User: &protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{ Id: userID.String(), SecuritySettings: &protocol.SecurityConfig{ @@ -1254,7 +1215,7 @@ func TestVMessGCMLengthAuthPlusNoTerminationSignal(t *testing.T) { Receiver: &protocol.ServerEndpoint{ Address: net.NewIPOrDomain(net.LocalHostIP), Port: uint32(serverPort), - User: &protocol.User{ + User: &protocol.User{ Account: serial.ToTypedMessage(&vmess.Account{ Id: userID.String(), SecuritySettings: &protocol.SecurityConfig{ diff --git a/transport/internet/hysteria/config.go b/transport/internet/hysteria/config.go index 7636983f..37bff909 100644 --- a/transport/internet/hysteria/config.go +++ b/transport/internet/hysteria/config.go @@ -48,6 +48,8 @@ const protocolName = "hysteria" func init() { common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} { - return new(Config) + return &Config{ + UdpIdleTimeout: 60, + } })) } diff --git a/transport/internet/kcp/config.go b/transport/internet/kcp/config.go index fd51118c..f5407948 100644 --- a/transport/internet/kcp/config.go +++ b/transport/internet/kcp/config.go @@ -5,56 +5,8 @@ import ( "github.com/xtls/xray-core/transport/internet" ) -// GetMTUValue returns the value of MTU settings. -func (c *Config) GetMTUValue() uint32 { - if c == nil || c.Mtu == nil { - return 1350 - } - return c.Mtu.Value -} - -// GetTTIValue returns the value of TTI settings. -func (c *Config) GetTTIValue() uint32 { - if c == nil || c.Tti == nil { - return 50 - } - return c.Tti.Value -} - -// GetUplinkCapacityValue returns the value of UplinkCapacity settings. -func (c *Config) GetUplinkCapacityValue() uint32 { - if c == nil || c.UplinkCapacity == nil { - return 5 - } - return c.UplinkCapacity.Value -} - -// GetDownlinkCapacityValue returns the value of DownlinkCapacity settings. -func (c *Config) GetDownlinkCapacityValue() uint32 { - if c == nil || c.DownlinkCapacity == nil { - return 20 - } - return c.DownlinkCapacity.Value -} - -// GetWriteBufferSize returns the size of WriterBuffer in bytes. -func (c *Config) GetWriteBufferSize() uint32 { - if c == nil || c.WriteBuffer == nil { - return 2 * 1024 * 1024 - } - return c.WriteBuffer.Size -} - -// GetReadBufferSize returns the size of ReadBuffer in bytes. -// func (c *Config) GetReadBufferSize() uint32 { -// if c == nil || c.ReadBuffer == nil { -// return 2 * 1024 * 1024 -// } -// return c.ReadBuffer.Size -// } - func (c *Config) GetSendingInFlightSize() uint32 { - size := c.GetUplinkCapacityValue() * 1024 * 1024 / c.GetMTUValue() / (1000 / c.GetTTIValue()) + size := c.UplinkCapacity * 1024 * 1024 / c.Mtu / (1000 / c.Tti) if size < 8 { size = 8 } @@ -62,23 +14,26 @@ func (c *Config) GetSendingInFlightSize() uint32 { } func (c *Config) GetSendingBufferSize() uint32 { - return c.GetWriteBufferSize() / c.GetMTUValue() + return c.MaxSendingWindow / c.Mtu } func (c *Config) GetReceivingInFlightSize() uint32 { - size := c.GetDownlinkCapacityValue() * 1024 * 1024 / c.GetMTUValue() / (1000 / c.GetTTIValue()) + size := c.DownlinkCapacity * 1024 * 1024 / c.Mtu / (1000 / c.Tti) if size < 8 { size = 8 } return size } -// func (c *Config) GetReceivingBufferSize() uint32 { -// return c.GetReadBufferSize() / c.GetMTUValue() -// } - func init() { - common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} { - return new(Config) + common.Must(internet.RegisterProtocolConfigCreator(ProtocolName, func() interface{} { + return &Config{ + Mtu: 1350, + Tti: 50, + UplinkCapacity: 5, + DownlinkCapacity: 20, + CwndMultiplier: 1, + MaxSendingWindow: 2 * 1024 * 1024, + } })) } diff --git a/transport/internet/kcp/config.pb.go b/transport/internet/kcp/config.pb.go index 8a03702b..2c22efe9 100644 --- a/transport/internet/kcp/config.pb.go +++ b/transport/internet/kcp/config.pb.go @@ -7,7 +7,6 @@ package kcp import ( - serial "github.com/xtls/xray-core/common/serial" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -22,385 +21,21 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// Maximum Transmission Unit, in bytes. -type MTU struct { - state protoimpl.MessageState `protogen:"open.v1"` - Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *MTU) Reset() { - *x = MTU{} - mi := &file_transport_internet_kcp_config_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *MTU) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*MTU) ProtoMessage() {} - -func (x *MTU) ProtoReflect() protoreflect.Message { - mi := &file_transport_internet_kcp_config_proto_msgTypes[0] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use MTU.ProtoReflect.Descriptor instead. -func (*MTU) Descriptor() ([]byte, []int) { - return file_transport_internet_kcp_config_proto_rawDescGZIP(), []int{0} -} - -func (x *MTU) GetValue() uint32 { - if x != nil { - return x.Value - } - return 0 -} - -// Transmission Time Interview, in milli-sec. -type TTI struct { - state protoimpl.MessageState `protogen:"open.v1"` - Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *TTI) Reset() { - *x = TTI{} - mi := &file_transport_internet_kcp_config_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *TTI) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TTI) ProtoMessage() {} - -func (x *TTI) ProtoReflect() protoreflect.Message { - mi := &file_transport_internet_kcp_config_proto_msgTypes[1] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TTI.ProtoReflect.Descriptor instead. -func (*TTI) Descriptor() ([]byte, []int) { - return file_transport_internet_kcp_config_proto_rawDescGZIP(), []int{1} -} - -func (x *TTI) GetValue() uint32 { - if x != nil { - return x.Value - } - return 0 -} - -// Uplink capacity, in MB. -type UplinkCapacity struct { - state protoimpl.MessageState `protogen:"open.v1"` - Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *UplinkCapacity) Reset() { - *x = UplinkCapacity{} - mi := &file_transport_internet_kcp_config_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *UplinkCapacity) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UplinkCapacity) ProtoMessage() {} - -func (x *UplinkCapacity) ProtoReflect() protoreflect.Message { - mi := &file_transport_internet_kcp_config_proto_msgTypes[2] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UplinkCapacity.ProtoReflect.Descriptor instead. -func (*UplinkCapacity) Descriptor() ([]byte, []int) { - return file_transport_internet_kcp_config_proto_rawDescGZIP(), []int{2} -} - -func (x *UplinkCapacity) GetValue() uint32 { - if x != nil { - return x.Value - } - return 0 -} - -// Downlink capacity, in MB. -type DownlinkCapacity struct { - state protoimpl.MessageState `protogen:"open.v1"` - Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *DownlinkCapacity) Reset() { - *x = DownlinkCapacity{} - mi := &file_transport_internet_kcp_config_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *DownlinkCapacity) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DownlinkCapacity) ProtoMessage() {} - -func (x *DownlinkCapacity) ProtoReflect() protoreflect.Message { - mi := &file_transport_internet_kcp_config_proto_msgTypes[3] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DownlinkCapacity.ProtoReflect.Descriptor instead. -func (*DownlinkCapacity) Descriptor() ([]byte, []int) { - return file_transport_internet_kcp_config_proto_rawDescGZIP(), []int{3} -} - -func (x *DownlinkCapacity) GetValue() uint32 { - if x != nil { - return x.Value - } - return 0 -} - -type WriteBuffer struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Buffer size in bytes. - Size uint32 `protobuf:"varint,1,opt,name=size,proto3" json:"size,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *WriteBuffer) Reset() { - *x = WriteBuffer{} - mi := &file_transport_internet_kcp_config_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *WriteBuffer) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*WriteBuffer) ProtoMessage() {} - -func (x *WriteBuffer) ProtoReflect() protoreflect.Message { - mi := &file_transport_internet_kcp_config_proto_msgTypes[4] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use WriteBuffer.ProtoReflect.Descriptor instead. -func (*WriteBuffer) Descriptor() ([]byte, []int) { - return file_transport_internet_kcp_config_proto_rawDescGZIP(), []int{4} -} - -func (x *WriteBuffer) GetSize() uint32 { - if x != nil { - return x.Size - } - return 0 -} - -type ReadBuffer struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Buffer size in bytes. - Size uint32 `protobuf:"varint,1,opt,name=size,proto3" json:"size,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *ReadBuffer) Reset() { - *x = ReadBuffer{} - mi := &file_transport_internet_kcp_config_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *ReadBuffer) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ReadBuffer) ProtoMessage() {} - -func (x *ReadBuffer) ProtoReflect() protoreflect.Message { - mi := &file_transport_internet_kcp_config_proto_msgTypes[5] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ReadBuffer.ProtoReflect.Descriptor instead. -func (*ReadBuffer) Descriptor() ([]byte, []int) { - return file_transport_internet_kcp_config_proto_rawDescGZIP(), []int{5} -} - -func (x *ReadBuffer) GetSize() uint32 { - if x != nil { - return x.Size - } - return 0 -} - -type ConnectionReuse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Enable bool `protobuf:"varint,1,opt,name=enable,proto3" json:"enable,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *ConnectionReuse) Reset() { - *x = ConnectionReuse{} - mi := &file_transport_internet_kcp_config_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *ConnectionReuse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ConnectionReuse) ProtoMessage() {} - -func (x *ConnectionReuse) ProtoReflect() protoreflect.Message { - mi := &file_transport_internet_kcp_config_proto_msgTypes[6] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ConnectionReuse.ProtoReflect.Descriptor instead. -func (*ConnectionReuse) Descriptor() ([]byte, []int) { - return file_transport_internet_kcp_config_proto_rawDescGZIP(), []int{6} -} - -func (x *ConnectionReuse) GetEnable() bool { - if x != nil { - return x.Enable - } - return false -} - -// Pre-shared secret between client and server. It is used for traffic obfuscation. -// Note that if seed is absent in the config, the traffic will still be obfuscated, -// but by a predefined algorithm. -type EncryptionSeed struct { - state protoimpl.MessageState `protogen:"open.v1"` - Seed string `protobuf:"bytes,1,opt,name=seed,proto3" json:"seed,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *EncryptionSeed) Reset() { - *x = EncryptionSeed{} - mi := &file_transport_internet_kcp_config_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *EncryptionSeed) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*EncryptionSeed) ProtoMessage() {} - -func (x *EncryptionSeed) ProtoReflect() protoreflect.Message { - mi := &file_transport_internet_kcp_config_proto_msgTypes[7] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use EncryptionSeed.ProtoReflect.Descriptor instead. -func (*EncryptionSeed) Descriptor() ([]byte, []int) { - return file_transport_internet_kcp_config_proto_rawDescGZIP(), []int{7} -} - -func (x *EncryptionSeed) GetSeed() string { - if x != nil { - return x.Seed - } - return "" -} - type Config struct { state protoimpl.MessageState `protogen:"open.v1"` - Mtu *MTU `protobuf:"bytes,1,opt,name=mtu,proto3" json:"mtu,omitempty"` - Tti *TTI `protobuf:"bytes,2,opt,name=tti,proto3" json:"tti,omitempty"` - UplinkCapacity *UplinkCapacity `protobuf:"bytes,3,opt,name=uplink_capacity,json=uplinkCapacity,proto3" json:"uplink_capacity,omitempty"` - DownlinkCapacity *DownlinkCapacity `protobuf:"bytes,4,opt,name=downlink_capacity,json=downlinkCapacity,proto3" json:"downlink_capacity,omitempty"` - Congestion bool `protobuf:"varint,5,opt,name=congestion,proto3" json:"congestion,omitempty"` - WriteBuffer *WriteBuffer `protobuf:"bytes,6,opt,name=write_buffer,json=writeBuffer,proto3" json:"write_buffer,omitempty"` - ReadBuffer *ReadBuffer `protobuf:"bytes,7,opt,name=read_buffer,json=readBuffer,proto3" json:"read_buffer,omitempty"` - HeaderConfig *serial.TypedMessage `protobuf:"bytes,8,opt,name=header_config,json=headerConfig,proto3" json:"header_config,omitempty"` - Seed *EncryptionSeed `protobuf:"bytes,10,opt,name=seed,proto3" json:"seed,omitempty"` + Mtu uint32 `protobuf:"varint,1,opt,name=mtu,proto3" json:"mtu,omitempty"` + Tti uint32 `protobuf:"varint,2,opt,name=tti,proto3" json:"tti,omitempty"` + UplinkCapacity uint32 `protobuf:"varint,3,opt,name=uplink_capacity,json=uplinkCapacity,proto3" json:"uplink_capacity,omitempty"` + DownlinkCapacity uint32 `protobuf:"varint,4,opt,name=downlink_capacity,json=downlinkCapacity,proto3" json:"downlink_capacity,omitempty"` + CwndMultiplier uint32 `protobuf:"varint,5,opt,name=cwnd_multiplier,json=cwndMultiplier,proto3" json:"cwnd_multiplier,omitempty"` + MaxSendingWindow uint32 `protobuf:"varint,6,opt,name=max_sending_window,json=maxSendingWindow,proto3" json:"max_sending_window,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *Config) Reset() { *x = Config{} - mi := &file_transport_internet_kcp_config_proto_msgTypes[8] + mi := &file_transport_internet_kcp_config_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -412,7 +47,7 @@ func (x *Config) String() string { func (*Config) ProtoMessage() {} func (x *Config) ProtoReflect() protoreflect.Message { - mi := &file_transport_internet_kcp_config_proto_msgTypes[8] + mi := &file_transport_internet_kcp_config_proto_msgTypes[0] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -425,109 +60,63 @@ func (x *Config) ProtoReflect() protoreflect.Message { // Deprecated: Use Config.ProtoReflect.Descriptor instead. func (*Config) Descriptor() ([]byte, []int) { - return file_transport_internet_kcp_config_proto_rawDescGZIP(), []int{8} + return file_transport_internet_kcp_config_proto_rawDescGZIP(), []int{0} } -func (x *Config) GetMtu() *MTU { +func (x *Config) GetMtu() uint32 { if x != nil { return x.Mtu } - return nil + return 0 } -func (x *Config) GetTti() *TTI { +func (x *Config) GetTti() uint32 { if x != nil { return x.Tti } - return nil + return 0 } -func (x *Config) GetUplinkCapacity() *UplinkCapacity { +func (x *Config) GetUplinkCapacity() uint32 { if x != nil { return x.UplinkCapacity } - return nil + return 0 } -func (x *Config) GetDownlinkCapacity() *DownlinkCapacity { +func (x *Config) GetDownlinkCapacity() uint32 { if x != nil { return x.DownlinkCapacity } - return nil + return 0 } -func (x *Config) GetCongestion() bool { +func (x *Config) GetCwndMultiplier() uint32 { if x != nil { - return x.Congestion + return x.CwndMultiplier } - return false + return 0 } -func (x *Config) GetWriteBuffer() *WriteBuffer { +func (x *Config) GetMaxSendingWindow() uint32 { if x != nil { - return x.WriteBuffer + return x.MaxSendingWindow } - return nil -} - -func (x *Config) GetReadBuffer() *ReadBuffer { - if x != nil { - return x.ReadBuffer - } - return nil -} - -func (x *Config) GetHeaderConfig() *serial.TypedMessage { - if x != nil { - return x.HeaderConfig - } - return nil -} - -func (x *Config) GetSeed() *EncryptionSeed { - if x != nil { - return x.Seed - } - return nil + return 0 } var File_transport_internet_kcp_config_proto protoreflect.FileDescriptor const file_transport_internet_kcp_config_proto_rawDesc = "" + "\n" + - "#transport/internet/kcp/config.proto\x12\x1bxray.transport.internet.kcp\x1a!common/serial/typed_message.proto\"\x1b\n" + - "\x03MTU\x12\x14\n" + - "\x05value\x18\x01 \x01(\rR\x05value\"\x1b\n" + - "\x03TTI\x12\x14\n" + - "\x05value\x18\x01 \x01(\rR\x05value\"&\n" + - "\x0eUplinkCapacity\x12\x14\n" + - "\x05value\x18\x01 \x01(\rR\x05value\"(\n" + - "\x10DownlinkCapacity\x12\x14\n" + - "\x05value\x18\x01 \x01(\rR\x05value\"!\n" + - "\vWriteBuffer\x12\x12\n" + - "\x04size\x18\x01 \x01(\rR\x04size\" \n" + - "\n" + - "ReadBuffer\x12\x12\n" + - "\x04size\x18\x01 \x01(\rR\x04size\")\n" + - "\x0fConnectionReuse\x12\x16\n" + - "\x06enable\x18\x01 \x01(\bR\x06enable\"$\n" + - "\x0eEncryptionSeed\x12\x12\n" + - "\x04seed\x18\x01 \x01(\tR\x04seed\"\xe7\x04\n" + - "\x06Config\x122\n" + - "\x03mtu\x18\x01 \x01(\v2 .xray.transport.internet.kcp.MTUR\x03mtu\x122\n" + - "\x03tti\x18\x02 \x01(\v2 .xray.transport.internet.kcp.TTIR\x03tti\x12T\n" + - "\x0fuplink_capacity\x18\x03 \x01(\v2+.xray.transport.internet.kcp.UplinkCapacityR\x0euplinkCapacity\x12Z\n" + - "\x11downlink_capacity\x18\x04 \x01(\v2-.xray.transport.internet.kcp.DownlinkCapacityR\x10downlinkCapacity\x12\x1e\n" + - "\n" + - "congestion\x18\x05 \x01(\bR\n" + - "congestion\x12K\n" + - "\fwrite_buffer\x18\x06 \x01(\v2(.xray.transport.internet.kcp.WriteBufferR\vwriteBuffer\x12H\n" + - "\vread_buffer\x18\a \x01(\v2'.xray.transport.internet.kcp.ReadBufferR\n" + - "readBuffer\x12E\n" + - "\rheader_config\x18\b \x01(\v2 .xray.common.serial.TypedMessageR\fheaderConfig\x12?\n" + - "\x04seed\x18\n" + - " \x01(\v2+.xray.transport.internet.kcp.EncryptionSeedR\x04seedJ\x04\b\t\x10\n" + - "Bs\n" + + "#transport/internet/kcp/config.proto\x12\x1bxray.transport.internet.kcp\"\xd9\x01\n" + + "\x06Config\x12\x10\n" + + "\x03mtu\x18\x01 \x01(\rR\x03mtu\x12\x10\n" + + "\x03tti\x18\x02 \x01(\rR\x03tti\x12'\n" + + "\x0fuplink_capacity\x18\x03 \x01(\rR\x0euplinkCapacity\x12+\n" + + "\x11downlink_capacity\x18\x04 \x01(\rR\x10downlinkCapacity\x12'\n" + + "\x0fcwnd_multiplier\x18\x05 \x01(\rR\x0ecwndMultiplier\x12,\n" + + "\x12max_sending_window\x18\x06 \x01(\rR\x10maxSendingWindowBs\n" + "\x1fcom.xray.transport.internet.kcpP\x01Z0github.com/xtls/xray-core/transport/internet/kcp\xaa\x02\x1bXray.Transport.Internet.Kcpb\x06proto3" var ( @@ -542,33 +131,16 @@ func file_transport_internet_kcp_config_proto_rawDescGZIP() []byte { return file_transport_internet_kcp_config_proto_rawDescData } -var file_transport_internet_kcp_config_proto_msgTypes = make([]protoimpl.MessageInfo, 9) +var file_transport_internet_kcp_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_transport_internet_kcp_config_proto_goTypes = []any{ - (*MTU)(nil), // 0: xray.transport.internet.kcp.MTU - (*TTI)(nil), // 1: xray.transport.internet.kcp.TTI - (*UplinkCapacity)(nil), // 2: xray.transport.internet.kcp.UplinkCapacity - (*DownlinkCapacity)(nil), // 3: xray.transport.internet.kcp.DownlinkCapacity - (*WriteBuffer)(nil), // 4: xray.transport.internet.kcp.WriteBuffer - (*ReadBuffer)(nil), // 5: xray.transport.internet.kcp.ReadBuffer - (*ConnectionReuse)(nil), // 6: xray.transport.internet.kcp.ConnectionReuse - (*EncryptionSeed)(nil), // 7: xray.transport.internet.kcp.EncryptionSeed - (*Config)(nil), // 8: xray.transport.internet.kcp.Config - (*serial.TypedMessage)(nil), // 9: xray.common.serial.TypedMessage + (*Config)(nil), // 0: xray.transport.internet.kcp.Config } var file_transport_internet_kcp_config_proto_depIdxs = []int32{ - 0, // 0: xray.transport.internet.kcp.Config.mtu:type_name -> xray.transport.internet.kcp.MTU - 1, // 1: xray.transport.internet.kcp.Config.tti:type_name -> xray.transport.internet.kcp.TTI - 2, // 2: xray.transport.internet.kcp.Config.uplink_capacity:type_name -> xray.transport.internet.kcp.UplinkCapacity - 3, // 3: xray.transport.internet.kcp.Config.downlink_capacity:type_name -> xray.transport.internet.kcp.DownlinkCapacity - 4, // 4: xray.transport.internet.kcp.Config.write_buffer:type_name -> xray.transport.internet.kcp.WriteBuffer - 5, // 5: xray.transport.internet.kcp.Config.read_buffer:type_name -> xray.transport.internet.kcp.ReadBuffer - 9, // 6: xray.transport.internet.kcp.Config.header_config:type_name -> xray.common.serial.TypedMessage - 7, // 7: xray.transport.internet.kcp.Config.seed:type_name -> xray.transport.internet.kcp.EncryptionSeed - 8, // [8:8] is the sub-list for method output_type - 8, // [8:8] is the sub-list for method input_type - 8, // [8:8] is the sub-list for extension type_name - 8, // [8:8] is the sub-list for extension extendee - 0, // [0:8] is the sub-list for field type_name + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name } func init() { file_transport_internet_kcp_config_proto_init() } @@ -582,7 +154,7 @@ func file_transport_internet_kcp_config_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_kcp_config_proto_rawDesc), len(file_transport_internet_kcp_config_proto_rawDesc)), NumEnums: 0, - NumMessages: 9, + NumMessages: 1, NumExtensions: 0, NumServices: 0, }, diff --git a/transport/internet/kcp/config.proto b/transport/internet/kcp/config.proto index 8690f09f..b7d3529a 100644 --- a/transport/internet/kcp/config.proto +++ b/transport/internet/kcp/config.proto @@ -6,58 +6,11 @@ option go_package = "github.com/xtls/xray-core/transport/internet/kcp"; option java_package = "com.xray.transport.internet.kcp"; option java_multiple_files = true; -import "common/serial/typed_message.proto"; - -// Maximum Transmission Unit, in bytes. -message MTU { - uint32 value = 1; -} - -// Transmission Time Interview, in milli-sec. -message TTI { - uint32 value = 1; -} - -// Uplink capacity, in MB. -message UplinkCapacity { - uint32 value = 1; -} - -// Downlink capacity, in MB. -message DownlinkCapacity { - uint32 value = 1; -} - -message WriteBuffer { - // Buffer size in bytes. - uint32 size = 1; -} - -message ReadBuffer { - // Buffer size in bytes. - uint32 size = 1; -} - -message ConnectionReuse { - bool enable = 1; -} - -// Pre-shared secret between client and server. It is used for traffic obfuscation. -// Note that if seed is absent in the config, the traffic will still be obfuscated, -// but by a predefined algorithm. -message EncryptionSeed { - string seed = 1; -} - message Config { - MTU mtu = 1; - TTI tti = 2; - UplinkCapacity uplink_capacity = 3; - DownlinkCapacity downlink_capacity = 4; - bool congestion = 5; - WriteBuffer write_buffer = 6; - ReadBuffer read_buffer = 7; - xray.common.serial.TypedMessage header_config = 8; - reserved 9; - EncryptionSeed seed = 10; -} + uint32 mtu = 1; + uint32 tti = 2; + uint32 uplink_capacity = 3; + uint32 downlink_capacity = 4; + uint32 cwnd_multiplier = 5; + uint32 max_sending_window = 6; +} \ No newline at end of file diff --git a/transport/internet/kcp/connection.go b/transport/internet/kcp/connection.go index 90c4b7b8..f31e54f0 100644 --- a/transport/internet/kcp/connection.go +++ b/transport/internet/kcp/connection.go @@ -215,10 +215,10 @@ func NewConnection(meta ConnMetadata, writer io.Writer, closer io.Closer, config dataOutput: signal.NewNotifier(), Config: config, output: NewRetryableWriter(NewSegmentWriter(writer)), - mss: config.GetMTUValue() - DataSegmentOverhead, + mss: config.Mtu - DataSegmentOverhead, roundTrip: &RoundTripInfo{ rto: 100, - minRtt: config.GetTTIValue(), + minRtt: config.Tti, }, } @@ -232,7 +232,7 @@ func NewConnection(meta ConnMetadata, writer io.Writer, closer io.Closer, config return conn.State() == StateTerminated } conn.dataUpdater = NewUpdater( - config.GetTTIValue(), + config.Tti, func() bool { return !isTerminating() && (conn.sendingWorker.UpdateNecessary() || conn.receivingWorker.UpdateNecessary()) }, diff --git a/transport/internet/kcp/connection_test.go b/transport/internet/kcp/connection_test.go index 81bc6703..cf1a529d 100644 --- a/transport/internet/kcp/connection_test.go +++ b/transport/internet/kcp/connection_test.go @@ -16,7 +16,14 @@ func (NoOpCloser) Close() error { } func TestConnectionReadTimeout(t *testing.T) { - conn := NewConnection(ConnMetadata{Conversation: 1}, buf.DiscardBytes, NoOpCloser(0), &Config{}) + conn := NewConnection(ConnMetadata{Conversation: 1}, buf.DiscardBytes, NoOpCloser(0), &Config{ + Mtu: 1350, + Tti: 50, + UplinkCapacity: 5, + DownlinkCapacity: 20, + CwndMultiplier: 20, + MaxSendingWindow: 2 * 1024 * 1024, + }) conn.SetReadDeadline(time.Now().Add(time.Second)) b := make([]byte, 1024) diff --git a/transport/internet/kcp/dialer.go b/transport/internet/kcp/dialer.go index 310bbd53..8586d3e6 100644 --- a/transport/internet/kcp/dialer.go +++ b/transport/internet/kcp/dialer.go @@ -118,5 +118,5 @@ func DialKCP(ctx context.Context, dest net.Destination, streamSettings *internet } func init() { - common.Must(internet.RegisterTransportDialer(protocolName, DialKCP)) + common.Must(internet.RegisterTransportDialer(ProtocolName, DialKCP)) } diff --git a/transport/internet/kcp/kcp.go b/transport/internet/kcp/kcp.go index 31c0633c..fe556c1c 100644 --- a/transport/internet/kcp/kcp.go +++ b/transport/internet/kcp/kcp.go @@ -6,4 +6,4 @@ // xtaci@github for translating to Golang package kcp -const protocolName = "mkcp" +const ProtocolName = "mkcp" diff --git a/transport/internet/kcp/kcp_test.go b/transport/internet/kcp/kcp_test.go index 985d33d2..aabe0624 100644 --- a/transport/internet/kcp/kcp_test.go +++ b/transport/internet/kcp/kcp_test.go @@ -19,8 +19,15 @@ import ( func TestDialAndListen(t *testing.T) { listerner, err := NewListener(context.Background(), net.LocalHostIP, net.Port(0), &internet.MemoryStreamConfig{ - ProtocolName: "mkcp", - ProtocolSettings: &Config{}, + ProtocolName: "mkcp", + ProtocolSettings: &Config{ + Mtu: 1350, + Tti: 50, + UplinkCapacity: 5, + DownlinkCapacity: 20, + CwndMultiplier: 20, + MaxSendingWindow: 2 * 1024 * 1024, + }, }, func(conn stat.Connection) { go func(c stat.Connection) { payload := make([]byte, 4096) @@ -46,8 +53,15 @@ func TestDialAndListen(t *testing.T) { for i := 0; i < 10; i++ { errg.Go(func() error { clientConn, err := DialKCP(context.Background(), net.UDPDestination(net.LocalHostIP, port), &internet.MemoryStreamConfig{ - ProtocolName: "mkcp", - ProtocolSettings: &Config{}, + ProtocolName: "mkcp", + ProtocolSettings: &Config{ + Mtu: 1350, + Tti: 50, + UplinkCapacity: 5, + DownlinkCapacity: 20, + CwndMultiplier: 20, + MaxSendingWindow: 2 * 1024 * 1024, + }, }) if err != nil { return err diff --git a/transport/internet/kcp/listener.go b/transport/internet/kcp/listener.go index aabec65f..d2d28aed 100644 --- a/transport/internet/kcp/listener.go +++ b/transport/internet/kcp/listener.go @@ -174,5 +174,5 @@ func ListenKCP(ctx context.Context, address net.Address, port net.Port, streamSe } func init() { - common.Must(internet.RegisterTransportListener(protocolName, ListenKCP)) + common.Must(internet.RegisterTransportListener(ProtocolName, ListenKCP)) } diff --git a/transport/internet/kcp/sending.go b/transport/internet/kcp/sending.go index ac8e98c1..9dc1a76d 100644 --- a/transport/internet/kcp/sending.go +++ b/transport/internet/kcp/sending.go @@ -288,20 +288,22 @@ func (w *SendingWorker) Write(seg Segment) error { } func (w *SendingWorker) OnPacketLoss(lossRate uint32) { - if !w.conn.Config.Congestion || w.conn.roundTrip.Timeout() == 0 { + if w.conn.roundTrip.Timeout() == 0 { return } if lossRate >= 15 { w.controlWindow = 3 * w.controlWindow / 4 - } else if lossRate <= 5 { + } + if lossRate <= 5 { w.controlWindow += w.controlWindow / 4 } if w.controlWindow < 16 { w.controlWindow = 16 } - if w.controlWindow > 2*w.conn.Config.GetSendingInFlightSize() { - w.controlWindow = 2 * w.conn.Config.GetSendingInFlightSize() + cwnd := w.conn.Config.GetSendingInFlightSize() + if w.controlWindow > cwnd { + w.controlWindow = cwnd } } @@ -317,11 +319,11 @@ func (w *SendingWorker) Flush(current uint32) { if cwnd > w.remoteNextNumber-w.firstUnacknowledged { cwnd = w.remoteNextNumber - w.firstUnacknowledged } - if w.conn.Config.Congestion && cwnd > w.controlWindow { + if cwnd > w.controlWindow { cwnd = w.controlWindow } - cwnd *= 20 // magic + cwnd *= w.conn.Config.CwndMultiplier if !w.window.IsEmpty() { w.window.Flush(current, w.conn.roundTrip.Timeout(), cwnd)