github.com/v2fly/v2ray-core/v4@v4.45.2/transport/internet/kcp/sending.go (about)

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