github.com/v2fly/v2ray-core/v4@v4.45.2/transport/internet/kcp/sending.go (about) 1 //go:build !confonly 2 // +build !confonly 3 4 package kcp 5 6 import ( 7 "container/list" 8 "sync" 9 10 "github.com/v2fly/v2ray-core/v4/common/buf" 11 ) 12 13 type SendingWindow struct { 14 cache *list.List 15 totalInFlightSize uint32 16 writer SegmentWriter 17 onPacketLoss func(uint32) 18 } 19 20 func NewSendingWindow(writer SegmentWriter, onPacketLoss func(uint32)) *SendingWindow { 21 window := &SendingWindow{ 22 cache: list.New(), 23 writer: writer, 24 onPacketLoss: onPacketLoss, 25 } 26 return window 27 } 28 29 func (sw *SendingWindow) Release() { 30 if sw == nil { 31 return 32 } 33 for sw.cache.Len() > 0 { 34 seg := sw.cache.Front().Value.(*DataSegment) 35 seg.Release() 36 sw.cache.Remove(sw.cache.Front()) 37 } 38 } 39 40 func (sw *SendingWindow) Len() uint32 { 41 return uint32(sw.cache.Len()) 42 } 43 44 func (sw *SendingWindow) IsEmpty() bool { 45 return sw.cache.Len() == 0 46 } 47 48 func (sw *SendingWindow) Push(number uint32, b *buf.Buffer) { 49 seg := NewDataSegment() 50 seg.Number = number 51 seg.payload = b 52 53 sw.cache.PushBack(seg) 54 } 55 56 func (sw *SendingWindow) FirstNumber() uint32 { 57 return sw.cache.Front().Value.(*DataSegment).Number 58 } 59 60 func (sw *SendingWindow) Clear(una uint32) { 61 for !sw.IsEmpty() { 62 seg := sw.cache.Front().Value.(*DataSegment) 63 if seg.Number >= una { 64 break 65 } 66 seg.Release() 67 sw.cache.Remove(sw.cache.Front()) 68 } 69 } 70 71 func (sw *SendingWindow) HandleFastAck(number uint32, rto uint32) { 72 if sw.IsEmpty() { 73 return 74 } 75 76 sw.Visit(func(seg *DataSegment) bool { 77 if number == seg.Number || number-seg.Number > 0x7FFFFFFF { 78 return false 79 } 80 81 if seg.transmit > 0 && seg.timeout > rto/3 { 82 seg.timeout -= rto / 3 83 } 84 return true 85 }) 86 } 87 88 func (sw *SendingWindow) Visit(visitor func(seg *DataSegment) bool) { 89 if sw.IsEmpty() { 90 return 91 } 92 93 for e := sw.cache.Front(); e != nil; e = e.Next() { 94 seg := e.Value.(*DataSegment) 95 if !visitor(seg) { 96 break 97 } 98 } 99 } 100 101 func (sw *SendingWindow) Flush(current uint32, rto uint32, maxInFlightSize uint32) { 102 if sw.IsEmpty() { 103 return 104 } 105 106 var lost uint32 107 var inFlightSize uint32 108 109 sw.Visit(func(segment *DataSegment) bool { 110 if current-segment.timeout >= 0x7FFFFFFF { 111 return true 112 } 113 if segment.transmit == 0 { 114 // First time 115 sw.totalInFlightSize++ 116 } else { 117 lost++ 118 } 119 segment.timeout = current + rto 120 121 segment.Timestamp = current 122 segment.transmit++ 123 sw.writer.Write(segment) 124 inFlightSize++ 125 return inFlightSize < maxInFlightSize 126 }) 127 128 if sw.onPacketLoss != nil && inFlightSize > 0 && sw.totalInFlightSize != 0 { 129 rate := lost * 100 / sw.totalInFlightSize 130 sw.onPacketLoss(rate) 131 } 132 } 133 134 func (sw *SendingWindow) Remove(number uint32) bool { 135 if sw.IsEmpty() { 136 return false 137 } 138 139 for e := sw.cache.Front(); e != nil; e = e.Next() { 140 seg := e.Value.(*DataSegment) 141 if seg.Number > number { 142 return false 143 } else if seg.Number == number { 144 if sw.totalInFlightSize > 0 { 145 sw.totalInFlightSize-- 146 } 147 seg.Release() 148 sw.cache.Remove(e) 149 return true 150 } 151 } 152 153 return false 154 } 155 156 type SendingWorker struct { 157 sync.RWMutex 158 conn *Connection 159 window *SendingWindow 160 firstUnacknowledged uint32 161 nextNumber uint32 162 remoteNextNumber uint32 163 controlWindow uint32 164 fastResend uint32 165 windowSize uint32 166 firstUnacknowledgedUpdated bool 167 closed bool 168 } 169 170 func NewSendingWorker(kcp *Connection) *SendingWorker { 171 worker := &SendingWorker{ 172 conn: kcp, 173 fastResend: 2, 174 remoteNextNumber: 32, 175 controlWindow: kcp.Config.GetSendingInFlightSize(), 176 windowSize: kcp.Config.GetSendingBufferSize(), 177 } 178 worker.window = NewSendingWindow(worker, worker.OnPacketLoss) 179 return worker 180 } 181 182 func (w *SendingWorker) Release() { 183 w.Lock() 184 w.window.Release() 185 w.closed = true 186 w.Unlock() 187 } 188 189 func (w *SendingWorker) ProcessReceivingNext(nextNumber uint32) { 190 w.Lock() 191 defer w.Unlock() 192 193 w.ProcessReceivingNextWithoutLock(nextNumber) 194 } 195 196 func (w *SendingWorker) ProcessReceivingNextWithoutLock(nextNumber uint32) { 197 w.window.Clear(nextNumber) 198 w.FindFirstUnacknowledged() 199 } 200 201 func (w *SendingWorker) FindFirstUnacknowledged() { 202 first := w.firstUnacknowledged 203 if !w.window.IsEmpty() { 204 w.firstUnacknowledged = w.window.FirstNumber() 205 } else { 206 w.firstUnacknowledged = w.nextNumber 207 } 208 if first != w.firstUnacknowledged { 209 w.firstUnacknowledgedUpdated = true 210 } 211 } 212 213 func (w *SendingWorker) processAck(number uint32) bool { 214 // number < v.firstUnacknowledged || number >= v.nextNumber 215 if number-w.firstUnacknowledged > 0x7FFFFFFF || number-w.nextNumber < 0x7FFFFFFF { 216 return false 217 } 218 219 removed := w.window.Remove(number) 220 if removed { 221 w.FindFirstUnacknowledged() 222 } 223 return removed 224 } 225 226 func (w *SendingWorker) ProcessSegment(current uint32, seg *AckSegment, rto uint32) { 227 defer seg.Release() 228 229 w.Lock() 230 defer w.Unlock() 231 232 if w.closed { 233 return 234 } 235 236 if w.remoteNextNumber < seg.ReceivingWindow { 237 w.remoteNextNumber = seg.ReceivingWindow 238 } 239 w.ProcessReceivingNextWithoutLock(seg.ReceivingNext) 240 241 if seg.IsEmpty() { 242 return 243 } 244 245 var maxack uint32 246 var maxackRemoved bool 247 for _, number := range seg.NumberList { 248 removed := w.processAck(number) 249 if maxack < number { 250 maxack = number 251 maxackRemoved = removed 252 } 253 } 254 255 if maxackRemoved { 256 w.window.HandleFastAck(maxack, rto) 257 if current-seg.Timestamp < 10000 { 258 w.conn.roundTrip.Update(current-seg.Timestamp, current) 259 } 260 } 261 } 262 263 func (w *SendingWorker) Push(b *buf.Buffer) bool { 264 w.Lock() 265 defer w.Unlock() 266 267 if w.closed { 268 return false 269 } 270 271 if w.window.Len() > w.windowSize { 272 return false 273 } 274 275 w.window.Push(w.nextNumber, b) 276 w.nextNumber++ 277 return true 278 } 279 280 func (w *SendingWorker) Write(seg Segment) error { 281 dataSeg := seg.(*DataSegment) 282 283 dataSeg.Conv = w.conn.meta.Conversation 284 dataSeg.SendingNext = w.firstUnacknowledged 285 dataSeg.Option = 0 286 if w.conn.State() == StateReadyToClose { 287 dataSeg.Option = SegmentOptionClose 288 } 289 290 return w.conn.output.Write(dataSeg) 291 } 292 293 func (w *SendingWorker) OnPacketLoss(lossRate uint32) { 294 if !w.conn.Config.Congestion || w.conn.roundTrip.Timeout() == 0 { 295 return 296 } 297 298 if lossRate >= 15 { 299 w.controlWindow = 3 * w.controlWindow / 4 300 } else if lossRate <= 5 { 301 w.controlWindow += w.controlWindow / 4 302 } 303 if w.controlWindow < 16 { 304 w.controlWindow = 16 305 } 306 if w.controlWindow > 2*w.conn.Config.GetSendingInFlightSize() { 307 w.controlWindow = 2 * w.conn.Config.GetSendingInFlightSize() 308 } 309 } 310 311 func (w *SendingWorker) Flush(current uint32) { 312 w.Lock() 313 314 if w.closed { 315 w.Unlock() 316 return 317 } 318 319 cwnd := w.conn.Config.GetSendingInFlightSize() 320 if cwnd > w.remoteNextNumber-w.firstUnacknowledged { 321 cwnd = w.remoteNextNumber - w.firstUnacknowledged 322 } 323 if w.conn.Config.Congestion && cwnd > w.controlWindow { 324 cwnd = w.controlWindow 325 } 326 327 cwnd *= 20 // magic 328 329 if !w.window.IsEmpty() { 330 w.window.Flush(current, w.conn.roundTrip.Timeout(), cwnd) 331 w.firstUnacknowledgedUpdated = false 332 } 333 334 updated := w.firstUnacknowledgedUpdated 335 w.firstUnacknowledgedUpdated = false 336 337 w.Unlock() 338 339 if updated { 340 w.conn.Ping(current, CommandPing) 341 } 342 } 343 344 func (w *SendingWorker) CloseWrite() { 345 w.Lock() 346 defer w.Unlock() 347 348 w.window.Clear(0xFFFFFFFF) 349 } 350 351 func (w *SendingWorker) IsEmpty() bool { 352 w.RLock() 353 defer w.RUnlock() 354 355 return w.window.IsEmpty() 356 } 357 358 func (w *SendingWorker) UpdateNecessary() bool { 359 return !w.IsEmpty() 360 } 361 362 func (w *SendingWorker) FirstUnacknowledged() uint32 { 363 w.RLock() 364 defer w.RUnlock() 365 366 return w.firstUnacknowledged 367 }