|  | @@ -0,0 +1,155 @@
 | 
	
		
			
				|  |  | +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
 | 
	
		
			
				|  |  | +}
 |