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 }