mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-05-08 14:13:22 +00:00
mKCP transport: Add cwndMultiplier; Apply unaggressive strategy by default (#5890)
https://github.com/XTLS/Xray-core/issues/4846#issuecomment-4150329444 https://github.com/XTLS/Xray-core/pull/5872#issuecomment-4184774915 https://github.com/XTLS/Xray-core/pull/5890#issuecomment-4240052251
This commit is contained in:
@@ -14,6 +14,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/platform/filesystem"
|
"github.com/xtls/xray-core/common/platform/filesystem"
|
||||||
@@ -54,64 +55,57 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type KCPConfig struct {
|
type KCPConfig struct {
|
||||||
Mtu *uint32 `json:"mtu"`
|
Mtu *uint32 `json:"mtu"`
|
||||||
Tti *uint32 `json:"tti"`
|
Tti *uint32 `json:"tti"`
|
||||||
UpCap *uint32 `json:"uplinkCapacity"`
|
UpCap *uint32 `json:"uplinkCapacity"`
|
||||||
DownCap *uint32 `json:"downlinkCapacity"`
|
DownCap *uint32 `json:"downlinkCapacity"`
|
||||||
Congestion *bool `json:"congestion"`
|
CwndMultiplier *uint32 `json:"cwndMultiplier"`
|
||||||
ReadBufferSize *uint32 `json:"readBufferSize"`
|
MaxSendingWindow *uint32 `json:"maxSendingWindow"`
|
||||||
WriteBufferSize *uint32 `json:"writeBufferSize"`
|
|
||||||
HeaderConfig json.RawMessage `json:"header"`
|
HeaderConfig json.RawMessage `json:"header"`
|
||||||
Seed *string `json:"seed"`
|
Seed *string `json:"seed"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build implements Buildable.
|
// Build implements Buildable.
|
||||||
func (c *KCPConfig) Build() (proto.Message, error) {
|
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 {
|
if c.HeaderConfig != nil || c.Seed != nil {
|
||||||
return nil, errors.PrintRemovedFeatureError("mkcp header & seed", "finalmask/udp header-* & mkcp-original & mkcp-aes128gcm")
|
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
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/testing/servers/tcp"
|
"github.com/xtls/xray-core/testing/servers/tcp"
|
||||||
"github.com/xtls/xray-core/testing/servers/udp"
|
"github.com/xtls/xray-core/testing/servers/udp"
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
"github.com/xtls/xray-core/transport/internet/kcp"
|
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -94,9 +93,9 @@ func TestVMessGCM(t *testing.T) {
|
|||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: &protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
Port: uint32(serverPort),
|
Port: uint32(serverPort),
|
||||||
User: &protocol.User{
|
User: &protocol.User{
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
Type: protocol.SecurityType_AES128_GCM,
|
Type: protocol.SecurityType_AES128_GCM,
|
||||||
},
|
},
|
||||||
@@ -192,9 +191,9 @@ func TestVMessGCMReadv(t *testing.T) {
|
|||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: &protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
Port: uint32(serverPort),
|
Port: uint32(serverPort),
|
||||||
User: &protocol.User{
|
User: &protocol.User{
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
Type: protocol.SecurityType_AES128_GCM,
|
Type: protocol.SecurityType_AES128_GCM,
|
||||||
},
|
},
|
||||||
@@ -293,9 +292,9 @@ func TestVMessGCMUDP(t *testing.T) {
|
|||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: &protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
Port: uint32(serverPort),
|
Port: uint32(serverPort),
|
||||||
User: &protocol.User{
|
User: &protocol.User{
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
Type: protocol.SecurityType_AES128_GCM,
|
Type: protocol.SecurityType_AES128_GCM,
|
||||||
},
|
},
|
||||||
@@ -388,9 +387,9 @@ func TestVMessChacha20(t *testing.T) {
|
|||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: &protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
Port: uint32(serverPort),
|
Port: uint32(serverPort),
|
||||||
User: &protocol.User{
|
User: &protocol.User{
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
Type: protocol.SecurityType_CHACHA20_POLY1305,
|
Type: protocol.SecurityType_CHACHA20_POLY1305,
|
||||||
},
|
},
|
||||||
@@ -484,7 +483,7 @@ func TestVMessNone(t *testing.T) {
|
|||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: &protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
Port: uint32(serverPort),
|
Port: uint32(serverPort),
|
||||||
User: &protocol.User{
|
User: &protocol.User{
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
@@ -638,25 +637,6 @@ func TestVMessKCPLarge(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
StreamSettings: &internet.StreamConfig{
|
StreamSettings: &internet.StreamConfig{
|
||||||
ProtocolName: "mkcp",
|
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{
|
ProxySettings: serial.ToTypedMessage(&inbound.Config{
|
||||||
@@ -704,7 +684,7 @@ func TestVMessKCPLarge(t *testing.T) {
|
|||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: &protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
Port: uint32(serverPort),
|
Port: uint32(serverPort),
|
||||||
User: &protocol.User{
|
User: &protocol.User{
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
@@ -717,25 +697,6 @@ func TestVMessKCPLarge(t *testing.T) {
|
|||||||
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
|
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
|
||||||
StreamSettings: &internet.StreamConfig{
|
StreamSettings: &internet.StreamConfig{
|
||||||
ProtocolName: "mkcp",
|
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{
|
Receiver: &protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
Port: uint32(serverPort),
|
Port: uint32(serverPort),
|
||||||
User: &protocol.User{
|
User: &protocol.User{
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
@@ -956,7 +917,7 @@ func TestVMessGCMMuxUDP(t *testing.T) {
|
|||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: &protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
Port: uint32(serverPort),
|
Port: uint32(serverPort),
|
||||||
User: &protocol.User{
|
User: &protocol.User{
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
@@ -1059,7 +1020,7 @@ func TestVMessZero(t *testing.T) {
|
|||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: &protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
Port: uint32(serverPort),
|
Port: uint32(serverPort),
|
||||||
User: &protocol.User{
|
User: &protocol.User{
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
@@ -1154,7 +1115,7 @@ func TestVMessGCMLengthAuth(t *testing.T) {
|
|||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: &protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
Port: uint32(serverPort),
|
Port: uint32(serverPort),
|
||||||
User: &protocol.User{
|
User: &protocol.User{
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
@@ -1254,7 +1215,7 @@ func TestVMessGCMLengthAuthPlusNoTerminationSignal(t *testing.T) {
|
|||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: &protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
Port: uint32(serverPort),
|
Port: uint32(serverPort),
|
||||||
User: &protocol.User{
|
User: &protocol.User{
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ const protocolName = "hysteria"
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {
|
common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {
|
||||||
return new(Config)
|
return &Config{
|
||||||
|
UdpIdleTimeout: 60,
|
||||||
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,56 +5,8 @@ import (
|
|||||||
"github.com/xtls/xray-core/transport/internet"
|
"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 {
|
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 {
|
if size < 8 {
|
||||||
size = 8
|
size = 8
|
||||||
}
|
}
|
||||||
@@ -62,23 +14,26 @@ func (c *Config) GetSendingInFlightSize() uint32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) GetSendingBufferSize() uint32 {
|
func (c *Config) GetSendingBufferSize() uint32 {
|
||||||
return c.GetWriteBufferSize() / c.GetMTUValue()
|
return c.MaxSendingWindow / c.Mtu
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) GetReceivingInFlightSize() uint32 {
|
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 {
|
if size < 8 {
|
||||||
size = 8
|
size = 8
|
||||||
}
|
}
|
||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (c *Config) GetReceivingBufferSize() uint32 {
|
|
||||||
// return c.GetReadBufferSize() / c.GetMTUValue()
|
|
||||||
// }
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {
|
common.Must(internet.RegisterProtocolConfigCreator(ProtocolName, func() interface{} {
|
||||||
return new(Config)
|
return &Config{
|
||||||
|
Mtu: 1350,
|
||||||
|
Tti: 50,
|
||||||
|
UplinkCapacity: 5,
|
||||||
|
DownlinkCapacity: 20,
|
||||||
|
CwndMultiplier: 1,
|
||||||
|
MaxSendingWindow: 2 * 1024 * 1024,
|
||||||
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
package kcp
|
package kcp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
serial "github.com/xtls/xray-core/common/serial"
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
@@ -22,385 +21,21 @@ const (
|
|||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = 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 {
|
type Config struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
Mtu *MTU `protobuf:"bytes,1,opt,name=mtu,proto3" json:"mtu,omitempty"`
|
Mtu uint32 `protobuf:"varint,1,opt,name=mtu,proto3" json:"mtu,omitempty"`
|
||||||
Tti *TTI `protobuf:"bytes,2,opt,name=tti,proto3" json:"tti,omitempty"`
|
Tti uint32 `protobuf:"varint,2,opt,name=tti,proto3" json:"tti,omitempty"`
|
||||||
UplinkCapacity *UplinkCapacity `protobuf:"bytes,3,opt,name=uplink_capacity,json=uplinkCapacity,proto3" json:"uplink_capacity,omitempty"`
|
UplinkCapacity uint32 `protobuf:"varint,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"`
|
DownlinkCapacity uint32 `protobuf:"varint,4,opt,name=downlink_capacity,json=downlinkCapacity,proto3" json:"downlink_capacity,omitempty"`
|
||||||
Congestion bool `protobuf:"varint,5,opt,name=congestion,proto3" json:"congestion,omitempty"`
|
CwndMultiplier uint32 `protobuf:"varint,5,opt,name=cwnd_multiplier,json=cwndMultiplier,proto3" json:"cwnd_multiplier,omitempty"`
|
||||||
WriteBuffer *WriteBuffer `protobuf:"bytes,6,opt,name=write_buffer,json=writeBuffer,proto3" json:"write_buffer,omitempty"`
|
MaxSendingWindow uint32 `protobuf:"varint,6,opt,name=max_sending_window,json=maxSendingWindow,proto3" json:"max_sending_window,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"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
*x = Config{}
|
*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 := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -412,7 +47,7 @@ func (x *Config) String() string {
|
|||||||
func (*Config) ProtoMessage() {}
|
func (*Config) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
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 {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -425,109 +60,63 @@ func (x *Config) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||||
func (*Config) Descriptor() ([]byte, []int) {
|
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 {
|
if x != nil {
|
||||||
return x.Mtu
|
return x.Mtu
|
||||||
}
|
}
|
||||||
return nil
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetTti() *TTI {
|
func (x *Config) GetTti() uint32 {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Tti
|
return x.Tti
|
||||||
}
|
}
|
||||||
return nil
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetUplinkCapacity() *UplinkCapacity {
|
func (x *Config) GetUplinkCapacity() uint32 {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.UplinkCapacity
|
return x.UplinkCapacity
|
||||||
}
|
}
|
||||||
return nil
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetDownlinkCapacity() *DownlinkCapacity {
|
func (x *Config) GetDownlinkCapacity() uint32 {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.DownlinkCapacity
|
return x.DownlinkCapacity
|
||||||
}
|
}
|
||||||
return nil
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetCongestion() bool {
|
func (x *Config) GetCwndMultiplier() uint32 {
|
||||||
if x != nil {
|
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 {
|
if x != nil {
|
||||||
return x.WriteBuffer
|
return x.MaxSendingWindow
|
||||||
}
|
}
|
||||||
return nil
|
return 0
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var File_transport_internet_kcp_config_proto protoreflect.FileDescriptor
|
var File_transport_internet_kcp_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_transport_internet_kcp_config_proto_rawDesc = "" +
|
const file_transport_internet_kcp_config_proto_rawDesc = "" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"#transport/internet/kcp/config.proto\x12\x1bxray.transport.internet.kcp\x1a!common/serial/typed_message.proto\"\x1b\n" +
|
"#transport/internet/kcp/config.proto\x12\x1bxray.transport.internet.kcp\"\xd9\x01\n" +
|
||||||
"\x03MTU\x12\x14\n" +
|
"\x06Config\x12\x10\n" +
|
||||||
"\x05value\x18\x01 \x01(\rR\x05value\"\x1b\n" +
|
"\x03mtu\x18\x01 \x01(\rR\x03mtu\x12\x10\n" +
|
||||||
"\x03TTI\x12\x14\n" +
|
"\x03tti\x18\x02 \x01(\rR\x03tti\x12'\n" +
|
||||||
"\x05value\x18\x01 \x01(\rR\x05value\"&\n" +
|
"\x0fuplink_capacity\x18\x03 \x01(\rR\x0euplinkCapacity\x12+\n" +
|
||||||
"\x0eUplinkCapacity\x12\x14\n" +
|
"\x11downlink_capacity\x18\x04 \x01(\rR\x10downlinkCapacity\x12'\n" +
|
||||||
"\x05value\x18\x01 \x01(\rR\x05value\"(\n" +
|
"\x0fcwnd_multiplier\x18\x05 \x01(\rR\x0ecwndMultiplier\x12,\n" +
|
||||||
"\x10DownlinkCapacity\x12\x14\n" +
|
"\x12max_sending_window\x18\x06 \x01(\rR\x10maxSendingWindowBs\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" +
|
|
||||||
"\x1fcom.xray.transport.internet.kcpP\x01Z0github.com/xtls/xray-core/transport/internet/kcp\xaa\x02\x1bXray.Transport.Internet.Kcpb\x06proto3"
|
"\x1fcom.xray.transport.internet.kcpP\x01Z0github.com/xtls/xray-core/transport/internet/kcp\xaa\x02\x1bXray.Transport.Internet.Kcpb\x06proto3"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -542,33 +131,16 @@ func file_transport_internet_kcp_config_proto_rawDescGZIP() []byte {
|
|||||||
return file_transport_internet_kcp_config_proto_rawDescData
|
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{
|
var file_transport_internet_kcp_config_proto_goTypes = []any{
|
||||||
(*MTU)(nil), // 0: xray.transport.internet.kcp.MTU
|
(*Config)(nil), // 0: xray.transport.internet.kcp.Config
|
||||||
(*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
|
|
||||||
}
|
}
|
||||||
var file_transport_internet_kcp_config_proto_depIdxs = []int32{
|
var file_transport_internet_kcp_config_proto_depIdxs = []int32{
|
||||||
0, // 0: xray.transport.internet.kcp.Config.mtu:type_name -> xray.transport.internet.kcp.MTU
|
0, // [0:0] is the sub-list for method output_type
|
||||||
1, // 1: xray.transport.internet.kcp.Config.tti:type_name -> xray.transport.internet.kcp.TTI
|
0, // [0:0] is the sub-list for method input_type
|
||||||
2, // 2: xray.transport.internet.kcp.Config.uplink_capacity:type_name -> xray.transport.internet.kcp.UplinkCapacity
|
0, // [0:0] is the sub-list for extension type_name
|
||||||
3, // 3: xray.transport.internet.kcp.Config.downlink_capacity:type_name -> xray.transport.internet.kcp.DownlinkCapacity
|
0, // [0:0] is the sub-list for extension extendee
|
||||||
4, // 4: xray.transport.internet.kcp.Config.write_buffer:type_name -> xray.transport.internet.kcp.WriteBuffer
|
0, // [0:0] is the sub-list for field type_name
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_transport_internet_kcp_config_proto_init() }
|
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(),
|
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)),
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_kcp_config_proto_rawDesc), len(file_transport_internet_kcp_config_proto_rawDesc)),
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 9,
|
NumMessages: 1,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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_package = "com.xray.transport.internet.kcp";
|
||||||
option java_multiple_files = true;
|
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 {
|
message Config {
|
||||||
MTU mtu = 1;
|
uint32 mtu = 1;
|
||||||
TTI tti = 2;
|
uint32 tti = 2;
|
||||||
UplinkCapacity uplink_capacity = 3;
|
uint32 uplink_capacity = 3;
|
||||||
DownlinkCapacity downlink_capacity = 4;
|
uint32 downlink_capacity = 4;
|
||||||
bool congestion = 5;
|
uint32 cwnd_multiplier = 5;
|
||||||
WriteBuffer write_buffer = 6;
|
uint32 max_sending_window = 6;
|
||||||
ReadBuffer read_buffer = 7;
|
}
|
||||||
xray.common.serial.TypedMessage header_config = 8;
|
|
||||||
reserved 9;
|
|
||||||
EncryptionSeed seed = 10;
|
|
||||||
}
|
|
||||||
@@ -215,10 +215,10 @@ func NewConnection(meta ConnMetadata, writer io.Writer, closer io.Closer, config
|
|||||||
dataOutput: signal.NewNotifier(),
|
dataOutput: signal.NewNotifier(),
|
||||||
Config: config,
|
Config: config,
|
||||||
output: NewRetryableWriter(NewSegmentWriter(writer)),
|
output: NewRetryableWriter(NewSegmentWriter(writer)),
|
||||||
mss: config.GetMTUValue() - DataSegmentOverhead,
|
mss: config.Mtu - DataSegmentOverhead,
|
||||||
roundTrip: &RoundTripInfo{
|
roundTrip: &RoundTripInfo{
|
||||||
rto: 100,
|
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
|
return conn.State() == StateTerminated
|
||||||
}
|
}
|
||||||
conn.dataUpdater = NewUpdater(
|
conn.dataUpdater = NewUpdater(
|
||||||
config.GetTTIValue(),
|
config.Tti,
|
||||||
func() bool {
|
func() bool {
|
||||||
return !isTerminating() && (conn.sendingWorker.UpdateNecessary() || conn.receivingWorker.UpdateNecessary())
|
return !isTerminating() && (conn.sendingWorker.UpdateNecessary() || conn.receivingWorker.UpdateNecessary())
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -16,7 +16,14 @@ func (NoOpCloser) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestConnectionReadTimeout(t *testing.T) {
|
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))
|
conn.SetReadDeadline(time.Now().Add(time.Second))
|
||||||
|
|
||||||
b := make([]byte, 1024)
|
b := make([]byte, 1024)
|
||||||
|
|||||||
@@ -118,5 +118,5 @@ func DialKCP(ctx context.Context, dest net.Destination, streamSettings *internet
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
common.Must(internet.RegisterTransportDialer(protocolName, DialKCP))
|
common.Must(internet.RegisterTransportDialer(ProtocolName, DialKCP))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,4 +6,4 @@
|
|||||||
// xtaci@github for translating to Golang
|
// xtaci@github for translating to Golang
|
||||||
package kcp
|
package kcp
|
||||||
|
|
||||||
const protocolName = "mkcp"
|
const ProtocolName = "mkcp"
|
||||||
|
|||||||
@@ -19,8 +19,15 @@ import (
|
|||||||
|
|
||||||
func TestDialAndListen(t *testing.T) {
|
func TestDialAndListen(t *testing.T) {
|
||||||
listerner, err := NewListener(context.Background(), net.LocalHostIP, net.Port(0), &internet.MemoryStreamConfig{
|
listerner, err := NewListener(context.Background(), net.LocalHostIP, net.Port(0), &internet.MemoryStreamConfig{
|
||||||
ProtocolName: "mkcp",
|
ProtocolName: "mkcp",
|
||||||
ProtocolSettings: &Config{},
|
ProtocolSettings: &Config{
|
||||||
|
Mtu: 1350,
|
||||||
|
Tti: 50,
|
||||||
|
UplinkCapacity: 5,
|
||||||
|
DownlinkCapacity: 20,
|
||||||
|
CwndMultiplier: 20,
|
||||||
|
MaxSendingWindow: 2 * 1024 * 1024,
|
||||||
|
},
|
||||||
}, func(conn stat.Connection) {
|
}, func(conn stat.Connection) {
|
||||||
go func(c stat.Connection) {
|
go func(c stat.Connection) {
|
||||||
payload := make([]byte, 4096)
|
payload := make([]byte, 4096)
|
||||||
@@ -46,8 +53,15 @@ func TestDialAndListen(t *testing.T) {
|
|||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
errg.Go(func() error {
|
errg.Go(func() error {
|
||||||
clientConn, err := DialKCP(context.Background(), net.UDPDestination(net.LocalHostIP, port), &internet.MemoryStreamConfig{
|
clientConn, err := DialKCP(context.Background(), net.UDPDestination(net.LocalHostIP, port), &internet.MemoryStreamConfig{
|
||||||
ProtocolName: "mkcp",
|
ProtocolName: "mkcp",
|
||||||
ProtocolSettings: &Config{},
|
ProtocolSettings: &Config{
|
||||||
|
Mtu: 1350,
|
||||||
|
Tti: 50,
|
||||||
|
UplinkCapacity: 5,
|
||||||
|
DownlinkCapacity: 20,
|
||||||
|
CwndMultiplier: 20,
|
||||||
|
MaxSendingWindow: 2 * 1024 * 1024,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -174,5 +174,5 @@ func ListenKCP(ctx context.Context, address net.Address, port net.Port, streamSe
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
common.Must(internet.RegisterTransportListener(protocolName, ListenKCP))
|
common.Must(internet.RegisterTransportListener(ProtocolName, ListenKCP))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -288,20 +288,22 @@ func (w *SendingWorker) Write(seg Segment) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *SendingWorker) OnPacketLoss(lossRate uint32) {
|
func (w *SendingWorker) OnPacketLoss(lossRate uint32) {
|
||||||
if !w.conn.Config.Congestion || w.conn.roundTrip.Timeout() == 0 {
|
if w.conn.roundTrip.Timeout() == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if lossRate >= 15 {
|
if lossRate >= 15 {
|
||||||
w.controlWindow = 3 * w.controlWindow / 4
|
w.controlWindow = 3 * w.controlWindow / 4
|
||||||
} else if lossRate <= 5 {
|
}
|
||||||
|
if lossRate <= 5 {
|
||||||
w.controlWindow += w.controlWindow / 4
|
w.controlWindow += w.controlWindow / 4
|
||||||
}
|
}
|
||||||
if w.controlWindow < 16 {
|
if w.controlWindow < 16 {
|
||||||
w.controlWindow = 16
|
w.controlWindow = 16
|
||||||
}
|
}
|
||||||
if w.controlWindow > 2*w.conn.Config.GetSendingInFlightSize() {
|
cwnd := w.conn.Config.GetSendingInFlightSize()
|
||||||
w.controlWindow = 2 * 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 {
|
if cwnd > w.remoteNextNumber-w.firstUnacknowledged {
|
||||||
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 = w.controlWindow
|
||||||
}
|
}
|
||||||
|
|
||||||
cwnd *= 20 // magic
|
cwnd *= w.conn.Config.CwndMultiplier
|
||||||
|
|
||||||
if !w.window.IsEmpty() {
|
if !w.window.IsEmpty() {
|
||||||
w.window.Flush(current, w.conn.roundTrip.Timeout(), cwnd)
|
w.window.Flush(current, w.conn.roundTrip.Timeout(), cwnd)
|
||||||
|
|||||||
Reference in New Issue
Block a user