|  | @@ -5,6 +5,7 @@ import (
 | 
	
		
			
				|  |  |  	"io"
 | 
	
		
			
				|  |  |  	"net"
 | 
	
		
			
				|  |  |  	"sync"
 | 
	
		
			
				|  |  | +	"sync/atomic"
 | 
	
		
			
				|  |  |  	"time"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	"github.com/v2ray/v2ray-core/common/alloc"
 | 
	
	
		
			
				|  | @@ -18,7 +19,7 @@ var (
 | 
	
		
			
				|  |  |  	errClosedConnection = errors.New("Connection closed.")
 | 
	
		
			
				|  |  |  )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -type State int
 | 
	
		
			
				|  |  | +type State int32
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  const (
 | 
	
		
			
				|  |  |  	StateActive       State = 0
 | 
	
	
		
			
				|  | @@ -37,9 +38,65 @@ func nowMillisec() int64 {
 | 
	
		
			
				|  |  |  	return now.Unix()*1000 + int64(now.Nanosecond()/1000000)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +type RountTripInfo struct {
 | 
	
		
			
				|  |  | +	sync.RWMutex
 | 
	
		
			
				|  |  | +	variation uint32
 | 
	
		
			
				|  |  | +	srtt      uint32
 | 
	
		
			
				|  |  | +	rto       uint32
 | 
	
		
			
				|  |  | +	minRtt    uint32
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +func (this *RountTripInfo) Update(rtt uint32) {
 | 
	
		
			
				|  |  | +	if rtt > 0x7FFFFFFF {
 | 
	
		
			
				|  |  | +		return
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	this.Lock()
 | 
	
		
			
				|  |  | +	defer this.Unlock()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	// https://tools.ietf.org/html/rfc6298
 | 
	
		
			
				|  |  | +	if this.srtt == 0 {
 | 
	
		
			
				|  |  | +		this.srtt = rtt
 | 
	
		
			
				|  |  | +		this.variation = rtt / 2
 | 
	
		
			
				|  |  | +	} else {
 | 
	
		
			
				|  |  | +		delta := rtt - this.srtt
 | 
	
		
			
				|  |  | +		if this.srtt > rtt {
 | 
	
		
			
				|  |  | +			delta = this.srtt - rtt
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		this.variation = (3*this.variation + delta) / 4
 | 
	
		
			
				|  |  | +		this.srtt = (7*this.srtt + rtt) / 8
 | 
	
		
			
				|  |  | +		if this.srtt < this.minRtt {
 | 
	
		
			
				|  |  | +			this.srtt = this.minRtt
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	var rto uint32
 | 
	
		
			
				|  |  | +	if this.minRtt < 4*this.variation {
 | 
	
		
			
				|  |  | +		rto = this.srtt + 4*this.variation
 | 
	
		
			
				|  |  | +	} else {
 | 
	
		
			
				|  |  | +		rto = this.srtt + this.variation
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if rto > 10000 {
 | 
	
		
			
				|  |  | +		rto = 10000
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	this.rto = rto * 3 / 2
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +func (this *RountTripInfo) Timeout() uint32 {
 | 
	
		
			
				|  |  | +	this.RLock()
 | 
	
		
			
				|  |  | +	defer this.RUnlock()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return this.rto
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +func (this *RountTripInfo) SmoothedTime() uint32 {
 | 
	
		
			
				|  |  | +	this.RLock()
 | 
	
		
			
				|  |  | +	defer this.RUnlock()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return this.srtt
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  // Connection is a KCP connection over UDP.
 | 
	
		
			
				|  |  |  type Connection struct {
 | 
	
		
			
				|  |  | -	sync.RWMutex
 | 
	
		
			
				|  |  |  	block         Authenticator
 | 
	
		
			
				|  |  |  	local, remote net.Addr
 | 
	
		
			
				|  |  |  	wd            time.Time // write deadline
 | 
	
	
		
			
				|  | @@ -54,9 +111,9 @@ type Connection struct {
 | 
	
		
			
				|  |  |  	sendingUpdated   bool
 | 
	
		
			
				|  |  |  	lastPingTime     uint32
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	mss                        uint32
 | 
	
		
			
				|  |  | -	rx_rttvar, rx_srtt, rx_rto uint32
 | 
	
		
			
				|  |  | -	interval                   uint32
 | 
	
		
			
				|  |  | +	mss       uint32
 | 
	
		
			
				|  |  | +	roundTrip *RountTripInfo
 | 
	
		
			
				|  |  | +	interval  uint32
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	receivingWorker *ReceivingWorker
 | 
	
		
			
				|  |  |  	sendingWorker   *SendingWorker
 | 
	
	
		
			
				|  | @@ -85,7 +142,10 @@ func NewConnection(conv uint16, writerCloser io.WriteCloser, local *net.UDPAddr,
 | 
	
		
			
				|  |  |  	conn.output = NewSegmentWriter(authWriter)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	conn.mss = authWriter.Mtu() - DataSegmentOverhead
 | 
	
		
			
				|  |  | -	conn.rx_rto = 100
 | 
	
		
			
				|  |  | +	conn.roundTrip = &RountTripInfo{
 | 
	
		
			
				|  |  | +		rto:    100,
 | 
	
		
			
				|  |  | +		minRtt: effectiveConfig.Tti,
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  |  	conn.interval = effectiveConfig.Tti
 | 
	
		
			
				|  |  |  	conn.receivingWorker = NewReceivingWorker(conn)
 | 
	
		
			
				|  |  |  	conn.fastresend = 2
 | 
	
	
		
			
				|  | @@ -107,8 +167,7 @@ func (this *Connection) Read(b []byte) (int, error) {
 | 
	
		
			
				|  |  |  		return 0, io.EOF
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	state := this.State()
 | 
	
		
			
				|  |  | -	if state == StateTerminating || state == StateTerminated {
 | 
	
		
			
				|  |  | +	if this.State() == StateTerminating || this.State() == StateTerminated {
 | 
	
		
			
				|  |  |  		return 0, io.EOF
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  	return this.receivingWorker.Read(b)
 | 
	
	
		
			
				|  | @@ -144,10 +203,8 @@ func (this *Connection) Write(b []byte) (int, error) {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  func (this *Connection) SetState(state State) {
 | 
	
		
			
				|  |  | -	this.Lock()
 | 
	
		
			
				|  |  | -	this.state = state
 | 
	
		
			
				|  |  | -	this.stateBeginTime = this.Elapsed()
 | 
	
		
			
				|  |  | -	this.Unlock()
 | 
	
		
			
				|  |  | +	atomic.StoreInt32((*int32)(&this.state), int32(state))
 | 
	
		
			
				|  |  | +	atomic.StoreUint32(&this.stateBeginTime, this.Elapsed())
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	switch state {
 | 
	
		
			
				|  |  |  	case StateReadyToClose:
 | 
	
	
		
			
				|  | @@ -297,42 +354,10 @@ func (this *Connection) OnPeerClosed() {
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -// https://tools.ietf.org/html/rfc6298
 | 
	
		
			
				|  |  | -func (this *Connection) update_ack(rtt int32) {
 | 
	
		
			
				|  |  | -	this.Lock()
 | 
	
		
			
				|  |  | -	defer this.Unlock()
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	if this.rx_srtt == 0 {
 | 
	
		
			
				|  |  | -		this.rx_srtt = uint32(rtt)
 | 
	
		
			
				|  |  | -		this.rx_rttvar = uint32(rtt) / 2
 | 
	
		
			
				|  |  | -	} else {
 | 
	
		
			
				|  |  | -		delta := rtt - int32(this.rx_srtt)
 | 
	
		
			
				|  |  | -		if delta < 0 {
 | 
	
		
			
				|  |  | -			delta = -delta
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		this.rx_rttvar = (3*this.rx_rttvar + uint32(delta)) / 4
 | 
	
		
			
				|  |  | -		this.rx_srtt = (7*this.rx_srtt + uint32(rtt)) / 8
 | 
	
		
			
				|  |  | -		if this.rx_srtt < this.interval {
 | 
	
		
			
				|  |  | -			this.rx_srtt = this.interval
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	var rto uint32
 | 
	
		
			
				|  |  | -	if this.interval < 4*this.rx_rttvar {
 | 
	
		
			
				|  |  | -		rto = this.rx_srtt + 4*this.rx_rttvar
 | 
	
		
			
				|  |  | -	} else {
 | 
	
		
			
				|  |  | -		rto = this.rx_srtt + this.interval
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	if rto > 10000 {
 | 
	
		
			
				|  |  | -		rto = 10000
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	this.rx_rto = rto * 3 / 2
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  // Input when you received a low level packet (eg. UDP packet), call it
 | 
	
		
			
				|  |  | -func (kcp *Connection) Input(data []byte) int {
 | 
	
		
			
				|  |  | -	current := kcp.Elapsed()
 | 
	
		
			
				|  |  | -	kcp.lastIncomingTime = current
 | 
	
		
			
				|  |  | +func (this *Connection) Input(data []byte) int {
 | 
	
		
			
				|  |  | +	current := this.Elapsed()
 | 
	
		
			
				|  |  | +	atomic.StoreUint32(&this.lastIncomingTime, current)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	var seg Segment
 | 
	
		
			
				|  |  |  	for {
 | 
	
	
		
			
				|  | @@ -343,26 +368,27 @@ func (kcp *Connection) Input(data []byte) int {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		switch seg := seg.(type) {
 | 
	
		
			
				|  |  |  		case *DataSegment:
 | 
	
		
			
				|  |  | -			kcp.HandleOption(seg.Opt)
 | 
	
		
			
				|  |  | -			kcp.receivingWorker.ProcessSegment(seg)
 | 
	
		
			
				|  |  | -			kcp.lastPayloadTime = current
 | 
	
		
			
				|  |  | +			this.HandleOption(seg.Opt)
 | 
	
		
			
				|  |  | +			this.receivingWorker.ProcessSegment(seg)
 | 
	
		
			
				|  |  | +			atomic.StoreUint32(&this.lastPayloadTime, current)
 | 
	
		
			
				|  |  |  		case *AckSegment:
 | 
	
		
			
				|  |  | -			kcp.HandleOption(seg.Opt)
 | 
	
		
			
				|  |  | -			kcp.sendingWorker.ProcessSegment(current, seg)
 | 
	
		
			
				|  |  | -			kcp.lastPayloadTime = current
 | 
	
		
			
				|  |  | +			this.HandleOption(seg.Opt)
 | 
	
		
			
				|  |  | +			this.sendingWorker.ProcessSegment(current, seg)
 | 
	
		
			
				|  |  | +			atomic.StoreUint32(&this.lastPayloadTime, current)
 | 
	
		
			
				|  |  |  		case *CmdOnlySegment:
 | 
	
		
			
				|  |  | -			kcp.HandleOption(seg.Opt)
 | 
	
		
			
				|  |  | +			this.HandleOption(seg.Opt)
 | 
	
		
			
				|  |  |  			if seg.Cmd == SegmentCommandTerminated {
 | 
	
		
			
				|  |  | -				if kcp.state == StateActive ||
 | 
	
		
			
				|  |  | -					kcp.state == StateReadyToClose ||
 | 
	
		
			
				|  |  | -					kcp.state == StatePeerClosed {
 | 
	
		
			
				|  |  | -					kcp.SetState(StateTerminating)
 | 
	
		
			
				|  |  | -				} else if kcp.state == StateTerminating {
 | 
	
		
			
				|  |  | -					kcp.SetState(StateTerminated)
 | 
	
		
			
				|  |  | +				state := this.State()
 | 
	
		
			
				|  |  | +				if state == StateActive ||
 | 
	
		
			
				|  |  | +					state == StateReadyToClose ||
 | 
	
		
			
				|  |  | +					state == StatePeerClosed {
 | 
	
		
			
				|  |  | +					this.SetState(StateTerminating)
 | 
	
		
			
				|  |  | +				} else if state == StateTerminating {
 | 
	
		
			
				|  |  | +					this.SetState(StateTerminated)
 | 
	
		
			
				|  |  |  				}
 | 
	
		
			
				|  |  |  			}
 | 
	
		
			
				|  |  | -			kcp.sendingWorker.ProcessReceivingNext(seg.ReceivinNext)
 | 
	
		
			
				|  |  | -			kcp.receivingWorker.ProcessSendingNext(seg.SendingNext)
 | 
	
		
			
				|  |  | +			this.sendingWorker.ProcessReceivingNext(seg.ReceivinNext)
 | 
	
		
			
				|  |  | +			this.receivingWorker.ProcessSendingNext(seg.SendingNext)
 | 
	
		
			
				|  |  |  		default:
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  	}
 | 
	
	
		
			
				|  | @@ -372,16 +398,15 @@ func (kcp *Connection) Input(data []byte) int {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  func (this *Connection) flush() {
 | 
	
		
			
				|  |  |  	current := this.Elapsed()
 | 
	
		
			
				|  |  | -	state := this.State()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	if state == StateTerminated {
 | 
	
		
			
				|  |  | +	if this.State() == StateTerminated {
 | 
	
		
			
				|  |  |  		return
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -	if state == StateActive && current-this.lastPayloadTime >= 30000 {
 | 
	
		
			
				|  |  | +	if this.State() == StateActive && current-this.lastPayloadTime >= 30000 {
 | 
	
		
			
				|  |  |  		this.Close()
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	if state == StateTerminating {
 | 
	
		
			
				|  |  | +	if this.State() == StateTerminating {
 | 
	
		
			
				|  |  |  		this.output.Write(&CmdOnlySegment{
 | 
	
		
			
				|  |  |  			Conv: this.conv,
 | 
	
		
			
				|  |  |  			Cmd:  SegmentCommandTerminated,
 | 
	
	
		
			
				|  | @@ -394,7 +419,7 @@ func (this *Connection) flush() {
 | 
	
		
			
				|  |  |  		return
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	if state == StateReadyToClose && current-this.stateBeginTime > 15000 {
 | 
	
		
			
				|  |  | +	if this.State() == StateReadyToClose && current-this.stateBeginTime > 15000 {
 | 
	
		
			
				|  |  |  		this.SetState(StateTerminating)
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -408,7 +433,7 @@ func (this *Connection) flush() {
 | 
	
		
			
				|  |  |  		seg.Cmd = SegmentCommandPing
 | 
	
		
			
				|  |  |  		seg.ReceivinNext = this.receivingWorker.nextNumber
 | 
	
		
			
				|  |  |  		seg.SendingNext = this.sendingWorker.firstUnacknowledged
 | 
	
		
			
				|  |  | -		if state == StateReadyToClose {
 | 
	
		
			
				|  |  | +		if this.State() == StateReadyToClose {
 | 
	
		
			
				|  |  |  			seg.Opt = SegmentOptionClose
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  		this.output.Write(seg)
 | 
	
	
		
			
				|  | @@ -423,8 +448,5 @@ func (this *Connection) flush() {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  func (this *Connection) State() State {
 | 
	
		
			
				|  |  | -	this.RLock()
 | 
	
		
			
				|  |  | -	defer this.RUnlock()
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	return this.state
 | 
	
		
			
				|  |  | +	return State(atomic.LoadInt32((*int32)(&this.state)))
 | 
	
		
			
				|  |  |  }
 |