1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-07-01 19:45:24 +00:00
v2fly/transport/internet/kcp/congestion.go
2016-12-23 00:24:28 +01:00

156 lines
2.7 KiB
Go

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
}