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 }