github.com/EagleQL/Xray-core@v1.4.3/transport/internet/kcp/sending.go (about)

     1  package kcp
     2  
     3  import (
     4  	"container/list"
     5  	"sync"
     6  
     7  	"github.com/xtls/xray-core/common/buf"
     8  )
     9  
    10  type SendingWindow struct {
    11  	cache             *list.List
    12  	totalInFlightSize uint32
    13  	writer            SegmentWriter
    14  	onPacketLoss      func(uint32)
    15  }
    16  
    17  func NewSendingWindow(writer SegmentWriter, onPacketLoss func(uint32)) *SendingWindow {
    18  	window := &SendingWindow{
    19  		cache:        list.New(),
    20  		writer:       writer,
    21  		onPacketLoss: onPacketLoss,
    22  	}
    23  	return window
    24  }
    25  
    26  func (sw *SendingWindow) Release() {
    27  	if sw == nil {
    28  		return
    29  	}
    30  	for sw.cache.Len() > 0 {
    31  		seg := sw.cache.Front().Value.(*DataSegment)
    32  		seg.Release()
    33  		sw.cache.Remove(sw.cache.Front())
    34  	}
    35  }
    36  
    37  func (sw *SendingWindow) Len() uint32 {
    38  	return uint32(sw.cache.Len())
    39  }
    40  
    41  func (sw *SendingWindow) IsEmpty() bool {
    42  	return sw.cache.Len() == 0
    43  }
    44  
    45  func (sw *SendingWindow) Push(number uint32, b *buf.Buffer) {
    46  	seg := NewDataSegment()
    47  	seg.Number = number
    48  	seg.payload = b
    49  
    50  	sw.cache.PushBack(seg)
    51  }
    52  
    53  func (sw *SendingWindow) FirstNumber() uint32 {
    54  	return sw.cache.Front().Value.(*DataSegment).Number
    55  }
    56  
    57  func (sw *SendingWindow) Clear(una uint32) {
    58  	for !sw.IsEmpty() {
    59  		seg := sw.cache.Front().Value.(*DataSegment)
    60  		if seg.Number >= una {
    61  			break
    62  		}
    63  		seg.Release()
    64  		sw.cache.Remove(sw.cache.Front())
    65  	}
    66  }
    67  
    68  func (sw *SendingWindow) HandleFastAck(number uint32, rto uint32) {
    69  	if sw.IsEmpty() {
    70  		return
    71  	}
    72  
    73  	sw.Visit(func(seg *DataSegment) bool {
    74  		if number == seg.Number || number-seg.Number > 0x7FFFFFFF {
    75  			return false
    76  		}
    77  
    78  		if seg.transmit > 0 && seg.timeout > rto/3 {
    79  			seg.timeout -= rto / 3
    80  		}
    81  		return true
    82  	})
    83  }
    84  
    85  func (sw *SendingWindow) Visit(visitor func(seg *DataSegment) bool) {
    86  	if sw.IsEmpty() {
    87  		return
    88  	}
    89  
    90  	for e := sw.cache.Front(); e != nil; e = e.Next() {
    91  		seg := e.Value.(*DataSegment)
    92  		if !visitor(seg) {
    93  			break
    94  		}
    95  	}
    96  }
    97  
    98  func (sw *SendingWindow) Flush(current uint32, rto uint32, maxInFlightSize uint32) {
    99  	if sw.IsEmpty() {
   100  		return
   101  	}
   102  
   103  	var lost uint32
   104  	var inFlightSize uint32
   105  
   106  	sw.Visit(func(segment *DataSegment) bool {
   107  		if current-segment.timeout >= 0x7FFFFFFF {
   108  			return true
   109  		}
   110  		if segment.transmit == 0 {
   111  			// First time
   112  			sw.totalInFlightSize++
   113  		} else {
   114  			lost++
   115  		}
   116  		segment.timeout = current + rto
   117  
   118  		segment.Timestamp = current
   119  		segment.transmit++
   120  		sw.writer.Write(segment)
   121  		inFlightSize++
   122  		return inFlightSize < maxInFlightSize
   123  	})
   124  
   125  	if sw.onPacketLoss != nil && inFlightSize > 0 && sw.totalInFlightSize != 0 {
   126  		rate := lost * 100 / sw.totalInFlightSize
   127  		sw.onPacketLoss(rate)
   128  	}
   129  }
   130  
   131  func (sw *SendingWindow) Remove(number uint32) bool {
   132  	if sw.IsEmpty() {
   133  		return false
   134  	}
   135  
   136  	for e := sw.cache.Front(); e != nil; e = e.Next() {
   137  		seg := e.Value.(*DataSegment)
   138  		if seg.Number > number {
   139  			return false
   140  		} else if seg.Number == number {
   141  			if sw.totalInFlightSize > 0 {
   142  				sw.totalInFlightSize--
   143  			}
   144  			seg.Release()
   145  			sw.cache.Remove(e)
   146  			return true
   147  		}
   148  	}
   149  
   150  	return false
   151  }
   152  
   153  type SendingWorker struct {
   154  	sync.RWMutex
   155  	conn                       *Connection
   156  	window                     *SendingWindow
   157  	firstUnacknowledged        uint32
   158  	nextNumber                 uint32
   159  	remoteNextNumber           uint32
   160  	controlWindow              uint32
   161  	fastResend                 uint32
   162  	windowSize                 uint32
   163  	firstUnacknowledgedUpdated bool
   164  	closed                     bool
   165  }
   166  
   167  func NewSendingWorker(kcp *Connection) *SendingWorker {
   168  	worker := &SendingWorker{
   169  		conn:             kcp,
   170  		fastResend:       2,
   171  		remoteNextNumber: 32,
   172  		controlWindow:    kcp.Config.GetSendingInFlightSize(),
   173  		windowSize:       kcp.Config.GetSendingBufferSize(),
   174  	}
   175  	worker.window = NewSendingWindow(worker, worker.OnPacketLoss)
   176  	return worker
   177  }
   178  
   179  func (w *SendingWorker) Release() {
   180  	w.Lock()
   181  	w.window.Release()
   182  	w.closed = true
   183  	w.Unlock()
   184  }
   185  
   186  func (w *SendingWorker) ProcessReceivingNext(nextNumber uint32) {
   187  	w.Lock()
   188  	defer w.Unlock()
   189  
   190  	w.ProcessReceivingNextWithoutLock(nextNumber)
   191  }
   192  
   193  func (w *SendingWorker) ProcessReceivingNextWithoutLock(nextNumber uint32) {
   194  	w.window.Clear(nextNumber)
   195  	w.FindFirstUnacknowledged()
   196  }
   197  
   198  func (w *SendingWorker) FindFirstUnacknowledged() {
   199  	first := w.firstUnacknowledged
   200  	if !w.window.IsEmpty() {
   201  		w.firstUnacknowledged = w.window.FirstNumber()
   202  	} else {
   203  		w.firstUnacknowledged = w.nextNumber
   204  	}
   205  	if first != w.firstUnacknowledged {
   206  		w.firstUnacknowledgedUpdated = true
   207  	}
   208  }
   209  
   210  func (w *SendingWorker) processAck(number uint32) bool {
   211  	// number < v.firstUnacknowledged || number >= v.nextNumber
   212  	if number-w.firstUnacknowledged > 0x7FFFFFFF || number-w.nextNumber < 0x7FFFFFFF {
   213  		return false
   214  	}
   215  
   216  	removed := w.window.Remove(number)
   217  	if removed {
   218  		w.FindFirstUnacknowledged()
   219  	}
   220  	return removed
   221  }
   222  
   223  func (w *SendingWorker) ProcessSegment(current uint32, seg *AckSegment, rto uint32) {
   224  	defer seg.Release()
   225  
   226  	w.Lock()
   227  	defer w.Unlock()
   228  
   229  	if w.closed {
   230  		return
   231  	}
   232  
   233  	if w.remoteNextNumber < seg.ReceivingWindow {
   234  		w.remoteNextNumber = seg.ReceivingWindow
   235  	}
   236  	w.ProcessReceivingNextWithoutLock(seg.ReceivingNext)
   237  
   238  	if seg.IsEmpty() {
   239  		return
   240  	}
   241  
   242  	var maxack uint32
   243  	var maxackRemoved bool
   244  	for _, number := range seg.NumberList {
   245  		removed := w.processAck(number)
   246  		if maxack < number {
   247  			maxack = number
   248  			maxackRemoved = removed
   249  		}
   250  	}
   251  
   252  	if maxackRemoved {
   253  		w.window.HandleFastAck(maxack, rto)
   254  		if current-seg.Timestamp < 10000 {
   255  			w.conn.roundTrip.Update(current-seg.Timestamp, current)
   256  		}
   257  	}
   258  }
   259  
   260  func (w *SendingWorker) Push(b *buf.Buffer) bool {
   261  	w.Lock()
   262  	defer w.Unlock()
   263  
   264  	if w.closed {
   265  		return false
   266  	}
   267  
   268  	if w.window.Len() > w.windowSize {
   269  		return false
   270  	}
   271  
   272  	w.window.Push(w.nextNumber, b)
   273  	w.nextNumber++
   274  	return true
   275  }
   276  
   277  func (w *SendingWorker) Write(seg Segment) error {
   278  	dataSeg := seg.(*DataSegment)
   279  
   280  	dataSeg.Conv = w.conn.meta.Conversation
   281  	dataSeg.SendingNext = w.firstUnacknowledged
   282  	dataSeg.Option = 0
   283  	if w.conn.State() == StateReadyToClose {
   284  		dataSeg.Option = SegmentOptionClose
   285  	}
   286  
   287  	return w.conn.output.Write(dataSeg)
   288  }
   289  
   290  func (w *SendingWorker) OnPacketLoss(lossRate uint32) {
   291  	if !w.conn.Config.Congestion || w.conn.roundTrip.Timeout() == 0 {
   292  		return
   293  	}
   294  
   295  	if lossRate >= 15 {
   296  		w.controlWindow = 3 * w.controlWindow / 4
   297  	} else if lossRate <= 5 {
   298  		w.controlWindow += w.controlWindow / 4
   299  	}
   300  	if w.controlWindow < 16 {
   301  		w.controlWindow = 16
   302  	}
   303  	if w.controlWindow > 2*w.conn.Config.GetSendingInFlightSize() {
   304  		w.controlWindow = 2 * w.conn.Config.GetSendingInFlightSize()
   305  	}
   306  }
   307  
   308  func (w *SendingWorker) Flush(current uint32) {
   309  	w.Lock()
   310  
   311  	if w.closed {
   312  		w.Unlock()
   313  		return
   314  	}
   315  
   316  	cwnd := w.conn.Config.GetSendingInFlightSize()
   317  	if cwnd > w.remoteNextNumber-w.firstUnacknowledged {
   318  		cwnd = w.remoteNextNumber - w.firstUnacknowledged
   319  	}
   320  	if w.conn.Config.Congestion && cwnd > w.controlWindow {
   321  		cwnd = w.controlWindow
   322  	}
   323  
   324  	cwnd *= 20 // magic
   325  
   326  	if !w.window.IsEmpty() {
   327  		w.window.Flush(current, w.conn.roundTrip.Timeout(), cwnd)
   328  		w.firstUnacknowledgedUpdated = false
   329  	}
   330  
   331  	updated := w.firstUnacknowledgedUpdated
   332  	w.firstUnacknowledgedUpdated = false
   333  
   334  	w.Unlock()
   335  
   336  	if updated {
   337  		w.conn.Ping(current, CommandPing)
   338  	}
   339  }
   340  
   341  func (w *SendingWorker) CloseWrite() {
   342  	w.Lock()
   343  	defer w.Unlock()
   344  
   345  	w.window.Clear(0xFFFFFFFF)
   346  }
   347  
   348  func (w *SendingWorker) IsEmpty() bool {
   349  	w.RLock()
   350  	defer w.RUnlock()
   351  
   352  	return w.window.IsEmpty()
   353  }
   354  
   355  func (w *SendingWorker) UpdateNecessary() bool {
   356  	return !w.IsEmpty()
   357  }
   358  
   359  func (w *SendingWorker) FirstUnacknowledged() uint32 {
   360  	w.RLock()
   361  	defer w.RUnlock()
   362  
   363  	return w.firstUnacknowledged
   364  }