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