diff --git a/common/common.go b/common/common.go index 3f23d295..3acee88e 100644 --- a/common/common.go +++ b/common/common.go @@ -8,6 +8,7 @@ import ( var ( ErrorAlreadyReleased = errors.New("Object already released.") + ErrBadConfiguration = errors.New("Bad configuration.") ) // Releasable interface is for those types that can release its members. diff --git a/transport/internet/kcp/config.go b/transport/internet/kcp/config.go index e98e5c2d..7b087f94 100644 --- a/transport/internet/kcp/config.go +++ b/transport/internet/kcp/config.go @@ -1,20 +1,32 @@ package kcp type Config struct { - Mtu int // Maximum transmission unit - Sndwnd int // Sending window size - Rcvwnd int // Receiving window size + Mtu int // Maximum transmission unit + Tti int + UplinkCapacity int + DownlinkCapacity int + Congestion bool } func (this *Config) Apply() { effectiveConfig = *this } +func (this *Config) GetSendingWindowSize() int { + return this.UplinkCapacity * 1024 * 1024 / this.Mtu / (1000 / this.Tti) +} + +func (this *Config) GetReceivingWindowSize() int { + return this.DownlinkCapacity * 1024 * 1024 / this.Mtu / (1000 / this.Tti) +} + func DefaultConfig() Config { return Config{ - Mtu: 1350, - Sndwnd: 1024, - Rcvwnd: 1024, + Mtu: 1350, + Tti: 20, + UplinkCapacity: 5, + DownlinkCapacity: 20, + Congestion: false, } } diff --git a/transport/internet/kcp/config_json.go b/transport/internet/kcp/config_json.go index 3d6aa6e6..c400078a 100644 --- a/transport/internet/kcp/config_json.go +++ b/transport/internet/kcp/config_json.go @@ -4,14 +4,18 @@ package kcp import ( "encoding/json" - "errors" + "github.com/v2ray/v2ray-core/common" "github.com/v2ray/v2ray-core/common/log" ) func (this *Config) UnmarshalJSON(data []byte) error { type JSONConfig struct { - Mtu *int `json:"mtu"` + Mtu *int `json:"mtu"` + Tti *int `json:"tti"` + UpCap *int `json:"uplinkCapacity"` + DownCap *int `json:"downlinkCapacity"` + Congestion *bool `json:"congestion"` } jsonConfig := new(JSONConfig) if err := json.Unmarshal(data, &jsonConfig); err != nil { @@ -21,9 +25,36 @@ func (this *Config) UnmarshalJSON(data []byte) error { mtu := *jsonConfig.Mtu if mtu < 576 || mtu > 1460 { log.Error("KCP|Config: Invalid MTU size: ", mtu) - return errors.New("Invalid configuration") + return common.ErrBadConfiguration } - this.Mtu = *jsonConfig.Mtu + this.Mtu = mtu + } + if jsonConfig.Tti != nil { + tti := *jsonConfig.Tti + if tti < 10 || tti > 100 { + log.Error("KCP|Config: Invalid TTI: ", tti) + return common.ErrBadConfiguration + } + this.Tti = tti + } + if jsonConfig.UpCap != nil { + upCap := *jsonConfig.UpCap + if upCap < 0 { + log.Error("KCP|Config: Invalid uplink capacity: ", upCap) + return common.ErrBadConfiguration + } + this.UplinkCapacity = upCap + } + if jsonConfig.DownCap != nil { + downCap := *jsonConfig.DownCap + if downCap < 0 { + log.Error("KCP|Config: Invalid downlink capacity: ", downCap) + return common.ErrBadConfiguration + } + this.DownlinkCapacity = downCap + } + if jsonConfig.Congestion != nil { + this.Congestion = *jsonConfig.Congestion } return nil diff --git a/transport/internet/kcp/connection.go b/transport/internet/kcp/connection.go index 7d465697..30bb455e 100644 --- a/transport/internet/kcp/connection.go +++ b/transport/internet/kcp/connection.go @@ -79,8 +79,8 @@ func NewConnection(conv uint32, writerCloser io.WriteCloser, local *net.UDPAddr, mtu := uint32(effectiveConfig.Mtu - block.HeaderSize() - headerSize) conn.kcp = NewKCP(conv, mtu, conn.output) - conn.kcp.WndSize(effectiveConfig.Sndwnd, effectiveConfig.Rcvwnd) - conn.kcp.NoDelay(1, 20, 2, 1) + conn.kcp.WndSize(effectiveConfig.GetSendingWindowSize(), effectiveConfig.GetReceivingWindowSize()) + conn.kcp.NoDelay(1, 20, 2, effectiveConfig.Congestion) conn.kcp.current = conn.Elapsed() go conn.updateTask() diff --git a/transport/internet/kcp/kcp.go b/transport/internet/kcp/kcp.go index a0a38b51..2ddebbc7 100644 --- a/transport/internet/kcp/kcp.go +++ b/transport/internet/kcp/kcp.go @@ -154,11 +154,11 @@ type KCP struct { acklist []uint32 - buffer []byte - fastresend int32 - nocwnd int32 - logmask int32 - output Output + buffer []byte + fastresend int32 + congestionControl bool + logmask int32 + output Output } // NewKCP create a new kcp control object, 'conv' must equal in two endpoint @@ -601,7 +601,7 @@ func (kcp *KCP) flush() { // calculate window size cwnd := _imin_(kcp.snd_wnd, kcp.rmt_wnd) - if kcp.nocwnd == 0 { + if kcp.congestionControl { cwnd = _imin_(kcp.cwnd, cwnd) } @@ -819,7 +819,7 @@ func (kcp *KCP) SetMtu(mtu int) int { // interval: internal update timer interval in millisec, default is 100ms // resend: 0:disable fast resend(default), 1:enable fast resend // nc: 0:normal congestion control(default), 1:disable congestion control -func (kcp *KCP) NoDelay(nodelay, interval, resend, nc int) int { +func (kcp *KCP) NoDelay(nodelay, interval, resend int, congestionControl bool) int { if nodelay >= 0 { kcp.nodelay = uint32(nodelay) if nodelay != 0 { @@ -839,9 +839,7 @@ func (kcp *KCP) NoDelay(nodelay, interval, resend, nc int) int { if resend >= 0 { kcp.fastresend = int32(resend) } - if nc >= 0 { - kcp.nocwnd = int32(nc) - } + kcp.congestionControl = congestionControl return 0 }