|  | @@ -2,8 +2,6 @@ package kcp
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import (
 | 
	
		
			
				|  |  |  	"sync"
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	"v2ray.com/core/common/alloc"
 | 
	
		
			
				|  |  |  )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  type SendingWindow struct {
 | 
	
	
		
			
				|  | @@ -67,6 +65,13 @@ func (this *SendingWindow) First() *DataSegment {
 | 
	
		
			
				|  |  |  	return this.data[this.start]
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +func (this *SendingWindow) Last() *DataSegment {
 | 
	
		
			
				|  |  | +	if this.IsEmpty() {
 | 
	
		
			
				|  |  | +		return nil
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	return this.data[this.last]
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  func (this *SendingWindow) Clear(una uint32) {
 | 
	
		
			
				|  |  |  	for !this.IsEmpty() && this.data[this.start].Number < una {
 | 
	
		
			
				|  |  |  		this.Remove(0)
 | 
	
	
		
			
				|  | @@ -171,80 +176,10 @@ func (this *SendingWindow) Flush(current uint32, resend uint32, rto uint32, maxI
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -type SendingQueue struct {
 | 
	
		
			
				|  |  | -	start uint32
 | 
	
		
			
				|  |  | -	cap   uint32
 | 
	
		
			
				|  |  | -	len   uint32
 | 
	
		
			
				|  |  | -	list  []*alloc.Buffer
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -func NewSendingQueue(size uint32) *SendingQueue {
 | 
	
		
			
				|  |  | -	return &SendingQueue{
 | 
	
		
			
				|  |  | -		start: 0,
 | 
	
		
			
				|  |  | -		cap:   size,
 | 
	
		
			
				|  |  | -		list:  make([]*alloc.Buffer, size),
 | 
	
		
			
				|  |  | -		len:   0,
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -func (this *SendingQueue) IsFull() bool {
 | 
	
		
			
				|  |  | -	return this.len == this.cap
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -func (this *SendingQueue) IsEmpty() bool {
 | 
	
		
			
				|  |  | -	return this.len == 0
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -func (this *SendingQueue) Pop() *alloc.Buffer {
 | 
	
		
			
				|  |  | -	if this.IsEmpty() {
 | 
	
		
			
				|  |  | -		return nil
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	seg := this.list[this.start]
 | 
	
		
			
				|  |  | -	this.list[this.start] = nil
 | 
	
		
			
				|  |  | -	this.len--
 | 
	
		
			
				|  |  | -	this.start++
 | 
	
		
			
				|  |  | -	if this.start == this.cap {
 | 
	
		
			
				|  |  | -		this.start = 0
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	if this.IsEmpty() {
 | 
	
		
			
				|  |  | -		this.start = 0
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	return seg
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -func (this *SendingQueue) Last() *alloc.Buffer {
 | 
	
		
			
				|  |  | -	if this.IsEmpty() {
 | 
	
		
			
				|  |  | -		return nil
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	return this.list[(this.start+this.len-1+this.cap)%this.cap]
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -func (this *SendingQueue) Push(seg *alloc.Buffer) {
 | 
	
		
			
				|  |  | -	if this.IsFull() {
 | 
	
		
			
				|  |  | -		return
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	this.list[(this.start+this.len)%this.cap] = seg
 | 
	
		
			
				|  |  | -	this.len++
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -func (this *SendingQueue) Clear() {
 | 
	
		
			
				|  |  | -	for i := uint32(0); i < this.len; i++ {
 | 
	
		
			
				|  |  | -		this.list[(i+this.start)%this.cap].Release()
 | 
	
		
			
				|  |  | -		this.list[(i+this.start)%this.cap] = nil
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	this.start = 0
 | 
	
		
			
				|  |  | -	this.len = 0
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -func (this *SendingQueue) Len() uint32 {
 | 
	
		
			
				|  |  | -	return this.len
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  type SendingWorker struct {
 | 
	
		
			
				|  |  |  	sync.RWMutex
 | 
	
		
			
				|  |  |  	conn                *Connection
 | 
	
		
			
				|  |  |  	window              *SendingWindow
 | 
	
		
			
				|  |  | -	queue               *SendingQueue
 | 
	
		
			
				|  |  |  	firstUnacknowledged uint32
 | 
	
		
			
				|  |  |  	nextNumber          uint32
 | 
	
		
			
				|  |  |  	remoteNextNumber    uint32
 | 
	
	
		
			
				|  | @@ -256,12 +191,11 @@ type SendingWorker struct {
 | 
	
		
			
				|  |  |  func NewSendingWorker(kcp *Connection) *SendingWorker {
 | 
	
		
			
				|  |  |  	worker := &SendingWorker{
 | 
	
		
			
				|  |  |  		conn:             kcp,
 | 
	
		
			
				|  |  | -		queue:            NewSendingQueue(effectiveConfig.GetSendingQueueSize()),
 | 
	
		
			
				|  |  |  		fastResend:       2,
 | 
	
		
			
				|  |  |  		remoteNextNumber: 32,
 | 
	
		
			
				|  |  |  		controlWindow:    effectiveConfig.GetSendingInFlightSize(),
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -	worker.window = NewSendingWindow(effectiveConfig.GetSendingWindowSize(), worker, worker.OnPacketLoss)
 | 
	
		
			
				|  |  | +	worker.window = NewSendingWindow(effectiveConfig.GetSendingQueueSize(), worker, worker.OnPacketLoss)
 | 
	
		
			
				|  |  |  	return worker
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -301,19 +235,6 @@ func (this *SendingWorker) ProcessAck(number uint32) {
 | 
	
		
			
				|  |  |  	this.FindFirstUnacknowledged()
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func (this *SendingWorker) FillWindow(current uint32) {
 | 
	
		
			
				|  |  | -	for !this.queue.IsEmpty() && !this.window.IsFull() {
 | 
	
		
			
				|  |  | -		seg := NewDataSegment()
 | 
	
		
			
				|  |  | -		seg.Data = this.queue.Pop()
 | 
	
		
			
				|  |  | -		seg.Number = this.nextNumber
 | 
	
		
			
				|  |  | -		seg.timeout = current
 | 
	
		
			
				|  |  | -		seg.ackSkipped = 0
 | 
	
		
			
				|  |  | -		seg.transmit = 0
 | 
	
		
			
				|  |  | -		this.window.Push(seg)
 | 
	
		
			
				|  |  | -		this.nextNumber++
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  func (this *SendingWorker) ProcessSegment(current uint32, seg *AckSegment) {
 | 
	
		
			
				|  |  |  	defer seg.Release()
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -339,33 +260,40 @@ func (this *SendingWorker) ProcessSegment(current uint32, seg *AckSegment) {
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	this.window.HandleFastAck(maxack)
 | 
	
		
			
				|  |  | -	this.FillWindow(current)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  func (this *SendingWorker) Push(b []byte) int {
 | 
	
		
			
				|  |  |  	nBytes := 0
 | 
	
		
			
				|  |  |  	this.Lock()
 | 
	
		
			
				|  |  |  	defer this.Unlock()
 | 
	
		
			
				|  |  | -	if !this.queue.IsEmpty() {
 | 
	
		
			
				|  |  | -		lastSeg := this.queue.Last()
 | 
	
		
			
				|  |  | -		if lastSeg.Len() < int(this.conn.mss) {
 | 
	
		
			
				|  |  | -			delta := int(this.conn.mss) - lastSeg.Len()
 | 
	
		
			
				|  |  | +	if !this.window.IsEmpty() {
 | 
	
		
			
				|  |  | +		lastSeg := this.window.Last()
 | 
	
		
			
				|  |  | +		dataLen := lastSeg.Data.Len()
 | 
	
		
			
				|  |  | +		if dataLen < int(this.conn.mss) {
 | 
	
		
			
				|  |  | +			delta := int(this.conn.mss) - dataLen
 | 
	
		
			
				|  |  |  			if delta > len(b) {
 | 
	
		
			
				|  |  |  				delta = len(b)
 | 
	
		
			
				|  |  |  			}
 | 
	
		
			
				|  |  | -			lastSeg.Append(b[:delta])
 | 
	
		
			
				|  |  | +			lastSeg.Data.Append(b[:delta])
 | 
	
		
			
				|  |  |  			b = b[delta:]
 | 
	
		
			
				|  |  |  			nBytes += delta
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -	for len(b) > 0 && !this.queue.IsFull() {
 | 
	
		
			
				|  |  | +	for len(b) > 0 && !this.window.IsFull() {
 | 
	
		
			
				|  |  |  		var size int
 | 
	
		
			
				|  |  |  		if len(b) > int(this.conn.mss) {
 | 
	
		
			
				|  |  |  			size = int(this.conn.mss)
 | 
	
		
			
				|  |  |  		} else {
 | 
	
		
			
				|  |  |  			size = len(b)
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  | -		this.queue.Push(AllocateBuffer().Clear().Append(b[:size]))
 | 
	
		
			
				|  |  | +		seg := NewDataSegment()
 | 
	
		
			
				|  |  | +		seg.Data = AllocateBuffer().Clear().Append(b[:size])
 | 
	
		
			
				|  |  | +		seg.Number = this.nextNumber
 | 
	
		
			
				|  |  | +		seg.timeout = 0
 | 
	
		
			
				|  |  | +		seg.ackSkipped = 0
 | 
	
		
			
				|  |  | +		seg.transmit = 0
 | 
	
		
			
				|  |  | +		this.window.Push(seg)
 | 
	
		
			
				|  |  | +		this.nextNumber++
 | 
	
		
			
				|  |  |  		b = b[size:]
 | 
	
		
			
				|  |  |  		nBytes += size
 | 
	
		
			
				|  |  |  	}
 | 
	
	
		
			
				|  | @@ -431,8 +359,9 @@ func (this *SendingWorker) Flush(current uint32) {
 | 
	
		
			
				|  |  |  		cwnd = this.firstUnacknowledged + this.controlWindow
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	this.FillWindow(current)
 | 
	
		
			
				|  |  | -	this.window.Flush(current, this.conn.fastresend, this.conn.roundTrip.Timeout(), cwnd)
 | 
	
		
			
				|  |  | +	if !this.window.IsEmpty() {
 | 
	
		
			
				|  |  | +		this.window.Flush(current, this.conn.fastresend, this.conn.roundTrip.Timeout(), cwnd)
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  func (this *SendingWorker) CloseWrite() {
 | 
	
	
		
			
				|  | @@ -440,12 +369,11 @@ func (this *SendingWorker) CloseWrite() {
 | 
	
		
			
				|  |  |  	defer this.Unlock()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	this.window.Clear(0xFFFFFFFF)
 | 
	
		
			
				|  |  | -	this.queue.Clear()
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  func (this *SendingWorker) IsEmpty() bool {
 | 
	
		
			
				|  |  |  	this.RLock()
 | 
	
		
			
				|  |  |  	defer this.RUnlock()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	return this.window.IsEmpty() && this.queue.IsEmpty()
 | 
	
		
			
				|  |  | +	return this.window.IsEmpty()
 | 
	
		
			
				|  |  |  }
 |