Skip to content

Commit 40f522b

Browse files
committed
2026-05-28 11:11:42
1 parent c17fa91 commit 40f522b

1 file changed

Lines changed: 26 additions & 21 deletions

File tree

protocol/etch/etch.go

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
228248
type 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

Comments
 (0)