@@ -223,6 +223,26 @@ type Pdu struct {
223223 seql uint32
224224}
225225
226+ // Rtt is an rfc6298 rtt estimator. Zero value is valid: the first sample initialises all fields.
227+ type Rtt struct {
228+ srtt time.Duration
229+ rttvar time.Duration
230+ rto time.Duration
231+ }
232+
233+ // Update folds a new rtt sample into the estimator.
234+ func (r * Rtt ) Update (sample time.Duration ) {
235+ switch {
236+ case r .srtt == 0 :
237+ r .srtt = sample
238+ r .rttvar = sample / 2
239+ case r .srtt != 0 :
240+ r .rttvar = (3 * r .rttvar + (r .srtt - sample ).Abs ()) / 4
241+ r .srtt = (7 * r .srtt + sample ) / 8
242+ }
243+ r .rto = min (max (r .srtt + 4 * r .rttvar , Conf .RTOMin ), Conf .RTOMax )
244+ }
245+
226246// Stream is a reliable bidirectional byte stream over the udp link. It implements io.ReadWriteCloser. All internal
227247// State is guarded by mu, and progress is announced via cnd.
228248type Stream struct {
@@ -252,9 +272,7 @@ type Stream struct {
252272 dupAckSeq uint32
253273
254274 // RTT estimator following rfc6298.
255- srtt time.Duration
256- rttvar time.Duration
257- rto time.Duration
275+ rtt Rtt
258276
259277 // Recv side.
260278 rcvBuf []byte // Contiguous bytes ready to be delivered to Read
@@ -283,7 +301,7 @@ func newConn(lnk io.ReadWriteCloser, addr net.Addr) *Stream {
283301 rwnd : uint32 (Conf .MaxSegmentSize ),
284302 cwnd : uint32 (Conf .MaxSegmentSize ),
285303 ssthresh : math .MaxUint32 ,
286- rto : Conf .RTONew ,
304+ rtt : Rtt { rto : Conf .RTONew } ,
287305 lastRecv : time .Now (),
288306 cancel : make (chan struct {}),
289307 }
@@ -362,7 +380,7 @@ func (c *Stream) flush() {
362380 seql : uint32 (n ),
363381 data : data ,
364382 sent : time .Now (),
365- rto : c .rto ,
383+ rto : c .rtt . rto ,
366384 }
367385 c .sndNxt += uint32 (n )
368386 c .inflight = append (c .inflight , seg )
@@ -380,7 +398,7 @@ func (c *Stream) flush() {
380398 seq : c .sndNxt ,
381399 seql : 1 ,
382400 sent : time .Now (),
383- rto : c .rto ,
401+ rto : c .rtt . rto ,
384402 }
385403 c .sndFinSeq = c .sndNxt
386404 c .sndFinDone = true
@@ -417,7 +435,7 @@ func (c *Stream) retransmit(now time.Time) {
417435 if seg .rto > Conf .RTOMax {
418436 seg .rto = Conf .RTOMax
419437 }
420- c .rto = seg .rto
438+ c .rtt . rto = seg .rto
421439 seg .sent = now
422440 var pl []byte
423441 if seg .cmd == cmdAck {
@@ -476,7 +494,7 @@ func (c *Stream) ack(ackNum uint32, win uint32) {
476494 if SeqLe (segEnd , ackNum ) {
477495 // Fully acked. Take an rtt sample only when this segment was not retransmitted.
478496 if seg .reno == 0 {
479- c .observeRTT (now .Sub (seg .sent ))
497+ c .rtt . Update (now .Sub (seg .sent ))
480498 }
481499 // Slow start vs congestion avoidance.
482500 mss := uint32 (Conf .MaxSegmentSize )
@@ -495,19 +513,6 @@ func (c *Stream) ack(ackNum uint32, win uint32) {
495513 c .cnd .Broadcast ()
496514}
497515
498- // ObserveRTT folds a new rtt sample into the estimator. Must be called with mu held.
499- func (c * Stream ) observeRTT (sample time.Duration ) {
500- switch {
501- case c .srtt == 0 :
502- c .srtt = sample
503- c .rttvar = sample / 2
504- case c .srtt != 0 :
505- c .rttvar = (3 * c .rttvar + (c .srtt - sample ).Abs ()) / 4
506- c .srtt = (7 * c .srtt + sample ) / 8
507- }
508- c .rto = min (max (c .srtt + 4 * c .rttvar , Conf .RTOMin ), Conf .RTOMax )
509- }
510-
511516// ============================================================================
512517// Recv path
513518// ============================================================================
0 commit comments