github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/transport/internet/kcp/receiving.go (about)

     1  package kcp
     2  
     3  import (
     4  	"sync"
     5  
     6  	"github.com/xtls/xray-core/common/buf"
     7  )
     8  
     9  type ReceivingWindow struct {
    10  	cache map[uint32]*DataSegment
    11  }
    12  
    13  func NewReceivingWindow() *ReceivingWindow {
    14  	return &ReceivingWindow{
    15  		cache: make(map[uint32]*DataSegment),
    16  	}
    17  }
    18  
    19  func (w *ReceivingWindow) Set(id uint32, value *DataSegment) bool {
    20  	_, f := w.cache[id]
    21  	if f {
    22  		return false
    23  	}
    24  	w.cache[id] = value
    25  	return true
    26  }
    27  
    28  func (w *ReceivingWindow) Has(id uint32) bool {
    29  	_, f := w.cache[id]
    30  	return f
    31  }
    32  
    33  func (w *ReceivingWindow) Remove(id uint32) *DataSegment {
    34  	v, f := w.cache[id]
    35  	if !f {
    36  		return nil
    37  	}
    38  	delete(w.cache, id)
    39  	return v
    40  }
    41  
    42  type AckList struct {
    43  	writer     SegmentWriter
    44  	timestamps []uint32
    45  	numbers    []uint32
    46  	nextFlush  []uint32
    47  
    48  	flushCandidates []uint32
    49  	dirty           bool
    50  }
    51  
    52  func NewAckList(writer SegmentWriter) *AckList {
    53  	return &AckList{
    54  		writer:          writer,
    55  		timestamps:      make([]uint32, 0, 128),
    56  		numbers:         make([]uint32, 0, 128),
    57  		nextFlush:       make([]uint32, 0, 128),
    58  		flushCandidates: make([]uint32, 0, 128),
    59  	}
    60  }
    61  
    62  func (l *AckList) Add(number uint32, timestamp uint32) {
    63  	l.timestamps = append(l.timestamps, timestamp)
    64  	l.numbers = append(l.numbers, number)
    65  	l.nextFlush = append(l.nextFlush, 0)
    66  	l.dirty = true
    67  }
    68  
    69  func (l *AckList) Clear(una uint32) {
    70  	count := 0
    71  	for i := 0; i < len(l.numbers); i++ {
    72  		if l.numbers[i] < una {
    73  			continue
    74  		}
    75  		if i != count {
    76  			l.numbers[count] = l.numbers[i]
    77  			l.timestamps[count] = l.timestamps[i]
    78  			l.nextFlush[count] = l.nextFlush[i]
    79  		}
    80  		count++
    81  	}
    82  	if count < len(l.numbers) {
    83  		l.numbers = l.numbers[:count]
    84  		l.timestamps = l.timestamps[:count]
    85  		l.nextFlush = l.nextFlush[:count]
    86  		l.dirty = true
    87  	}
    88  }
    89  
    90  func (l *AckList) Flush(current uint32, rto uint32) {
    91  	l.flushCandidates = l.flushCandidates[:0]
    92  
    93  	seg := NewAckSegment()
    94  	for i := 0; i < len(l.numbers); i++ {
    95  		if l.nextFlush[i] > current {
    96  			if len(l.flushCandidates) < cap(l.flushCandidates) {
    97  				l.flushCandidates = append(l.flushCandidates, l.numbers[i])
    98  			}
    99  			continue
   100  		}
   101  		seg.PutNumber(l.numbers[i])
   102  		seg.PutTimestamp(l.timestamps[i])
   103  		timeout := rto / 2
   104  		if timeout < 20 {
   105  			timeout = 20
   106  		}
   107  		l.nextFlush[i] = current + timeout
   108  
   109  		if seg.IsFull() {
   110  			l.writer.Write(seg)
   111  			seg.Release()
   112  			seg = NewAckSegment()
   113  			l.dirty = false
   114  		}
   115  	}
   116  
   117  	if l.dirty || !seg.IsEmpty() {
   118  		for _, number := range l.flushCandidates {
   119  			if seg.IsFull() {
   120  				break
   121  			}
   122  			seg.PutNumber(number)
   123  		}
   124  		l.writer.Write(seg)
   125  		l.dirty = false
   126  	}
   127  
   128  	seg.Release()
   129  }
   130  
   131  type ReceivingWorker struct {
   132  	sync.RWMutex
   133  	conn       *Connection
   134  	leftOver   buf.MultiBuffer
   135  	window     *ReceivingWindow
   136  	acklist    *AckList
   137  	nextNumber uint32
   138  	windowSize uint32
   139  }
   140  
   141  func NewReceivingWorker(kcp *Connection) *ReceivingWorker {
   142  	worker := &ReceivingWorker{
   143  		conn:       kcp,
   144  		window:     NewReceivingWindow(),
   145  		windowSize: kcp.Config.GetReceivingInFlightSize(),
   146  	}
   147  	worker.acklist = NewAckList(worker)
   148  	return worker
   149  }
   150  
   151  func (w *ReceivingWorker) Release() {
   152  	w.Lock()
   153  	buf.ReleaseMulti(w.leftOver)
   154  	w.leftOver = nil
   155  	w.Unlock()
   156  }
   157  
   158  func (w *ReceivingWorker) ProcessSendingNext(number uint32) {
   159  	w.Lock()
   160  	defer w.Unlock()
   161  
   162  	w.acklist.Clear(number)
   163  }
   164  
   165  func (w *ReceivingWorker) ProcessSegment(seg *DataSegment) {
   166  	w.Lock()
   167  	defer w.Unlock()
   168  
   169  	number := seg.Number
   170  	idx := number - w.nextNumber
   171  	if idx >= w.windowSize {
   172  		return
   173  	}
   174  	w.acklist.Clear(seg.SendingNext)
   175  	w.acklist.Add(number, seg.Timestamp)
   176  
   177  	if !w.window.Set(seg.Number, seg) {
   178  		seg.Release()
   179  	}
   180  }
   181  
   182  func (w *ReceivingWorker) ReadMultiBuffer() buf.MultiBuffer {
   183  	if w.leftOver != nil {
   184  		mb := w.leftOver
   185  		w.leftOver = nil
   186  		return mb
   187  	}
   188  
   189  	mb := make(buf.MultiBuffer, 0, 32)
   190  
   191  	w.Lock()
   192  	defer w.Unlock()
   193  	for {
   194  		seg := w.window.Remove(w.nextNumber)
   195  		if seg == nil {
   196  			break
   197  		}
   198  		w.nextNumber++
   199  		mb = append(mb, seg.Detach())
   200  		seg.Release()
   201  	}
   202  
   203  	return mb
   204  }
   205  
   206  func (w *ReceivingWorker) Read(b []byte) int {
   207  	mb := w.ReadMultiBuffer()
   208  	if mb.IsEmpty() {
   209  		return 0
   210  	}
   211  	mb, nBytes := buf.SplitBytes(mb, b)
   212  	if !mb.IsEmpty() {
   213  		w.leftOver = mb
   214  	}
   215  	return nBytes
   216  }
   217  
   218  func (w *ReceivingWorker) IsDataAvailable() bool {
   219  	w.RLock()
   220  	defer w.RUnlock()
   221  	return w.window.Has(w.nextNumber)
   222  }
   223  
   224  func (w *ReceivingWorker) NextNumber() uint32 {
   225  	w.RLock()
   226  	defer w.RUnlock()
   227  
   228  	return w.nextNumber
   229  }
   230  
   231  func (w *ReceivingWorker) Flush(current uint32) {
   232  	w.Lock()
   233  	defer w.Unlock()
   234  
   235  	w.acklist.Flush(current, w.conn.roundTrip.Timeout())
   236  }
   237  
   238  func (w *ReceivingWorker) Write(seg Segment) error {
   239  	ackSeg := seg.(*AckSegment)
   240  	ackSeg.Conv = w.conn.meta.Conversation
   241  	ackSeg.ReceivingNext = w.nextNumber
   242  	ackSeg.ReceivingWindow = w.nextNumber + w.windowSize
   243  	ackSeg.Option = 0
   244  	if w.conn.State() == StateReadyToClose {
   245  		ackSeg.Option = SegmentOptionClose
   246  	}
   247  	return w.conn.output.Write(ackSeg)
   248  }
   249  
   250  func (*ReceivingWorker) CloseRead() {
   251  }
   252  
   253  func (w *ReceivingWorker) UpdateNecessary() bool {
   254  	w.RLock()
   255  	defer w.RUnlock()
   256  
   257  	return len(w.acklist.numbers) > 0
   258  }