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

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