github.com/AntonOrnatskyi/goproxy@v0.0.0-20190205095733-4526a9fa18b4/core/dst/sendbuffer.go (about) 1 // Copyright 2014 The DST Authors. All rights reserved. 2 // Use of this source code is governed by an MIT-style 3 // license that can be found in the LICENSE file. 4 5 package dst 6 7 import ( 8 "fmt" 9 "runtime/debug" 10 11 "sync" 12 13 "github.com/juju/ratelimit" 14 ) 15 16 /* 17 sendWindow 18 v 19 [S|S|S|S|Q|Q|Q|Q| | | | | | | | | ] 20 ^ ^writeSlot 21 sendSlot 22 */ 23 type sendBuffer struct { 24 mux *Mux // we send packets here 25 scheduler *ratelimit.Bucket // sets send rate for packets 26 27 sendWindow int // maximum number of outstanding non-acked packets 28 packetRate int // target pps 29 30 send packetList // buffered packets 31 sendSlot int // buffer slot from which to send next packet 32 33 lost packetList // list of packets reported lost by timeout 34 lostSlot int // next lost packet to resend 35 36 closed bool 37 closing bool 38 mut sync.Mutex 39 cond *sync.Cond 40 } 41 42 const ( 43 schedulerRate = 1e6 44 schedulerCapacity = schedulerRate / 40 45 ) 46 47 // newSendBuffer creates a new send buffer with a zero window. 48 // SetRateAndWindow() must be called to set an initial packet rate and send 49 // window before using. 50 func newSendBuffer(m *Mux) *sendBuffer { 51 b := &sendBuffer{ 52 mux: m, 53 scheduler: ratelimit.NewBucketWithRate(schedulerRate, schedulerCapacity), 54 } 55 b.cond = sync.NewCond(&b.mut) 56 go func() { 57 defer func() { 58 if e := recover(); e != nil { 59 fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack())) 60 } 61 }() 62 b.writerLoop() 63 }() 64 return b 65 } 66 67 // Write puts a new packet in send buffer and schedules a send. Blocks when 68 // the window size is or would be exceeded. 69 func (b *sendBuffer) Write(pkt packet) error { 70 b.mut.Lock() 71 defer b.mut.Unlock() 72 73 for b.send.Full() || b.send.Len() >= b.sendWindow { 74 if b.closing { 75 return ErrClosedConn 76 } 77 if debugConnection { 78 log.Println(b, "Write blocked") 79 } 80 b.cond.Wait() 81 } 82 if !b.send.Append(pkt) { 83 panic("bug: append failed") 84 } 85 b.cond.Broadcast() 86 return nil 87 } 88 89 // Acknowledge removes packets with lower sequence numbers from the loss list 90 // or send buffer. 91 func (b *sendBuffer) Acknowledge(seq sequenceNo) { 92 b.mut.Lock() 93 94 if cut := b.lost.CutLessSeq(seq); cut > 0 { 95 if debugConnection { 96 log.Println(b, "cut", cut, "from loss list") 97 } 98 // Next resend should always start with the first packet, regardless 99 // of what we might already have resent previously. 100 b.lostSlot = 0 101 b.cond.Broadcast() 102 } 103 104 if cut := b.send.CutLessSeq(seq); cut > 0 { 105 if debugConnection { 106 log.Println(b, "cut", cut, "from send list") 107 } 108 b.sendSlot -= cut 109 b.cond.Broadcast() 110 } 111 112 b.mut.Unlock() 113 } 114 115 func (b *sendBuffer) NegativeAck(seq sequenceNo) { 116 b.mut.Lock() 117 118 pkts := b.send.PopSequence(seq) 119 if cut := len(pkts); cut > 0 { 120 b.lost.AppendAll(pkts) 121 if debugConnection { 122 log.Println(b, "cut", cut, "from send list, adding to loss list") 123 log.Println(seq, pkts) 124 } 125 b.sendSlot -= cut 126 b.lostSlot = 0 127 b.cond.Broadcast() 128 } 129 130 b.mut.Unlock() 131 } 132 133 // ScheduleResend arranges for a resend of all currently unacknowledged 134 // packets. 135 func (b *sendBuffer) ScheduleResend() { 136 b.mut.Lock() 137 138 if b.sendSlot > 0 { 139 // There are packets that have been sent but not acked. Move them from 140 // the send buffer to the loss list for retransmission. 141 if debugConnection { 142 log.Println(b, "scheduled resend from send list", b.sendSlot) 143 } 144 145 // Append the packets to the loss list and rewind the send buffer 146 b.lost.AppendAll(b.send.All()[:b.sendSlot]) 147 b.send.Cut(b.sendSlot) 148 b.sendSlot = 0 149 b.cond.Broadcast() 150 } 151 152 if b.lostSlot > 0 { 153 // Also resend whatever was already in the loss list 154 if debugConnection { 155 log.Println(b, "scheduled resend from loss list", b.lostSlot) 156 } 157 b.lostSlot = 0 158 b.cond.Broadcast() 159 } 160 161 b.mut.Unlock() 162 } 163 164 // SetWindowAndRate sets the window size (in packets) and packet rate (in 165 // packets per second) to use when sending. 166 func (b *sendBuffer) SetWindowAndRate(sendWindow, packetRate int) { 167 b.mut.Lock() 168 if debugConnection { 169 log.Println(b, "new window & rate", sendWindow, packetRate) 170 } 171 b.packetRate = packetRate 172 b.sendWindow = sendWindow 173 if b.sendWindow > b.send.Cap() { 174 b.send.Resize(b.sendWindow) 175 b.cond.Broadcast() 176 } 177 b.mut.Unlock() 178 } 179 180 // Stop stops the send buffer from any doing further sending, but waits for 181 // the current buffers to be drained. 182 func (b *sendBuffer) Stop() { 183 b.mut.Lock() 184 185 if b.closed || b.closing { 186 return 187 } 188 189 b.closing = true 190 for b.lost.Len() > 0 || b.send.Len() > 0 { 191 b.cond.Wait() 192 } 193 194 b.closed = true 195 b.cond.Broadcast() 196 b.mut.Unlock() 197 } 198 199 // CrashStop stops the send buffer from any doing further sending, without 200 // waiting for buffers to drain. 201 func (b *sendBuffer) CrashStop() { 202 b.mut.Lock() 203 204 if b.closed || b.closing { 205 return 206 } 207 208 b.closing = true 209 b.closed = true 210 b.cond.Broadcast() 211 b.mut.Unlock() 212 } 213 214 func (b *sendBuffer) String() string { 215 return fmt.Sprintf("sendBuffer@%p", b) 216 } 217 218 func (b *sendBuffer) writerLoop() { 219 if debugConnection { 220 log.Println(b, "writer() starting") 221 defer log.Println(b, "writer() exiting") 222 } 223 224 b.scheduler.Take(schedulerCapacity) 225 for { 226 var pkt packet 227 b.mut.Lock() 228 for b.lostSlot >= b.sendWindow || 229 (b.sendSlot == b.send.Len() && b.lostSlot == b.lost.Len()) { 230 if b.closed { 231 b.mut.Unlock() 232 return 233 } 234 235 if debugConnection { 236 log.Println(b, "writer() paused", b.lostSlot, b.sendSlot, b.sendWindow, b.lost.Len()) 237 } 238 b.cond.Wait() 239 } 240 241 if b.lostSlot < b.lost.Len() { 242 pkt = b.lost.All()[b.lostSlot] 243 pkt.hdr.timestamp = timestampMicros() 244 b.lostSlot++ 245 246 if debugConnection { 247 log.Println(b, "resend", b.lostSlot, b.lost.Len(), b.sendWindow, pkt.hdr.connID, pkt.hdr.sequenceNo) 248 } 249 } else if b.sendSlot < b.send.Len() { 250 pkt = b.send.All()[b.sendSlot] 251 pkt.hdr.timestamp = timestampMicros() 252 b.sendSlot++ 253 254 if debugConnection { 255 log.Println(b, "send", b.sendSlot, b.send.Len(), b.sendWindow, pkt.hdr.connID, pkt.hdr.sequenceNo) 256 } 257 } 258 259 b.cond.Broadcast() 260 packetRate := b.packetRate 261 b.mut.Unlock() 262 263 if pkt.dst != nil { 264 b.scheduler.Wait(schedulerRate / int64(packetRate)) 265 b.mux.write(pkt) 266 } 267 } 268 }