mirror of https://github.com/v2ray/v2ray-core
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
2.7 KiB
156 lines
2.7 KiB
8 years ago
|
package kcp
|
||
|
|
||
|
import (
|
||
|
"sync"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
defaultRTT = 100
|
||
|
queueSize = 10
|
||
|
)
|
||
|
|
||
|
type Queue struct {
|
||
|
value [queueSize]uint32
|
||
|
start uint32
|
||
|
length uint32
|
||
|
}
|
||
|
|
||
|
func (v *Queue) Push(value uint32) {
|
||
|
if v.length < queueSize {
|
||
|
v.value[v.length] = value
|
||
|
v.length++
|
||
|
return
|
||
|
}
|
||
|
v.value[v.start] = value
|
||
|
v.start++
|
||
|
if v.start == queueSize {
|
||
|
v.start = 0
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (v *Queue) Max() uint32 {
|
||
|
max := v.value[0]
|
||
|
for i := 1; i < queueSize; i++ {
|
||
|
if v.value[i] > max {
|
||
|
max = v.value[i]
|
||
|
}
|
||
|
}
|
||
|
return max
|
||
|
}
|
||
|
|
||
|
func (v *Queue) Min() uint32 {
|
||
|
max := v.value[0]
|
||
|
for i := 1; i < queueSize; i++ {
|
||
|
if v.value[i] < max {
|
||
|
max = v.value[i]
|
||
|
}
|
||
|
}
|
||
|
return max
|
||
|
}
|
||
|
|
||
|
type CongestionState byte
|
||
|
|
||
|
const (
|
||
|
CongestionStateRTTProbe CongestionState = iota
|
||
|
CongestionStateBandwidthProbe
|
||
|
CongestionStateTransfer
|
||
|
)
|
||
|
|
||
|
type Congestion struct {
|
||
|
sync.RWMutex
|
||
|
|
||
|
state CongestionState
|
||
|
stateSince uint32
|
||
|
limit uint32 // bytes per 1000 seconds
|
||
|
|
||
|
rtt uint32 // millisec
|
||
|
rttHistory Queue
|
||
|
rttUpdateTime uint32
|
||
|
|
||
|
initialThroughput uint32 // bytes per 1000 seconds
|
||
|
|
||
|
cycleStartTime uint32
|
||
|
cycleBytesConfirmed uint32
|
||
|
cycleBytesSent uint32
|
||
|
cycleBytesLimit uint32
|
||
|
|
||
|
cycle uint32
|
||
|
bestCycleBytesConfirmed uint32
|
||
|
bestCycleBytesSent uint32
|
||
|
}
|
||
|
|
||
|
func (v *Congestion) SetState(current uint32, state CongestionState) {
|
||
|
v.state = state
|
||
|
v.stateSince = current
|
||
|
}
|
||
|
|
||
|
func (v *Congestion) Update(current uint32) {
|
||
|
switch v.state {
|
||
|
case CongestionStateRTTProbe:
|
||
|
if v.rtt > 0 {
|
||
|
v.SetState(current, CongestionStateBandwidthProbe)
|
||
|
v.cycleStartTime = current
|
||
|
v.cycleBytesConfirmed = 0
|
||
|
v.cycleBytesSent = 0
|
||
|
v.cycleBytesLimit = v.initialThroughput * v.rtt / 1000 / 1000
|
||
|
}
|
||
|
case CongestionStateBandwidthProbe:
|
||
|
if current-v.cycleStartTime >= v.rtt {
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (v *Congestion) AddBytesConfirmed(current uint32, bytesConfirmed uint32) {
|
||
|
v.Lock()
|
||
|
defer v.Unlock()
|
||
|
|
||
|
v.cycleBytesConfirmed += bytesConfirmed
|
||
|
v.Update(current)
|
||
|
}
|
||
|
|
||
|
func (v *Congestion) UpdateRTT(current uint32, rtt uint32) {
|
||
|
v.Lock()
|
||
|
defer v.Unlock()
|
||
|
|
||
|
if v.state == CongestionStateRTTProbe || rtt < v.rtt {
|
||
|
v.rtt = rtt
|
||
|
v.rttUpdateTime = current
|
||
|
}
|
||
|
|
||
|
v.Update(current)
|
||
|
}
|
||
|
|
||
|
func (v *Congestion) GetBytesLimit() uint32 {
|
||
|
v.RLock()
|
||
|
defer v.RUnlock()
|
||
|
|
||
|
if v.state == CongestionStateRTTProbe {
|
||
|
return v.initialThroughput/1000/(1000/defaultRTT) - v.cycleBytesSent
|
||
|
}
|
||
|
|
||
|
return v.cycleBytesLimit
|
||
|
}
|
||
|
|
||
|
func (v *Congestion) RoundTripTime() uint32 {
|
||
|
v.RLock()
|
||
|
defer v.RUnlock()
|
||
|
|
||
|
if v.state == CongestionStateRTTProbe {
|
||
|
return defaultRTT
|
||
|
}
|
||
|
|
||
|
return v.rtt
|
||
|
}
|
||
|
|
||
|
func (v *Congestion) Timeout() uint32 {
|
||
|
v.RLock()
|
||
|
defer v.RUnlock()
|
||
|
|
||
|
if v.state == CongestionStateRTTProbe {
|
||
|
return defaultRTT * 3 / 2
|
||
|
}
|
||
|
|
||
|
return v.rtt * 3 / 2
|
||
|
}
|