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