Skip to content

Commit 5c2d3f3

Browse files
gbn: support dynamic resend timeouts
This commit adds support for setting the resend timeout dynamically for a connection. Prior to this commit, the timeout before a client or server resends the queue of packets, was always set to fixed value. A fixed timeout isn't suitable for all connections though, as the latency for different clients varies. With this commit, we instead add support for setting the resend timeout based on: * How long it took for the other party to respond during the handshake process * How long it took for the other party to respond with the connect ACK for a sent data packet. The timeout is set then to the time it took for the server to respond, multiplied by the resendMultiplier, unless the duration is shorter than the default resend timeout. Note though that if a connection's resend timeout is set manually set through the WithStaticResendTimeout, the resend timeout will always be set to that value, and won't be dynamically updated.
1 parent 17b8366 commit 5c2d3f3

File tree

3 files changed

+40
-7
lines changed

3 files changed

+40
-7
lines changed

gbn/gbn_client.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ func (g *GoBackNConn) clientHandshake() error {
9999
var (
100100
resp Message
101101
respSYN *PacketSYN
102+
resent bool
102103
)
103104
handshake:
104105
for {
@@ -115,6 +116,9 @@ handshake:
115116
return err
116117
}
117118

119+
// Notify the timeout manager that we sent a SYN.
120+
g.timeoutManager.Sent(msg, resent)
121+
118122
for {
119123
// Wait for SYN
120124
g.log.Debugf("Waiting for SYN")
@@ -135,6 +139,7 @@ handshake:
135139
case <-time.After(timeout):
136140
g.log.Debugf("SYN resendTimeout. Resending " +
137141
"SYN.")
142+
resent = true
138143

139144
continue handshake
140145
case <-g.quit:
@@ -173,6 +178,10 @@ handshake:
173178
return io.EOF
174179
}
175180

181+
// Notify the timeout manager we've received the SYN response from the
182+
// counterparty.
183+
g.timeoutManager.Received(resp)
184+
176185
// Send SYNACK
177186
g.log.Debugf("Sending SYNACK")
178187
synack, err := new(PacketSYNACK).Serialize()

gbn/gbn_conn.go

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func newGoBackNConn(ctx context.Context, cfg *config,
104104
s: cfg.n + 1,
105105
log: plog,
106106
sendPkt: func(packet *PacketData) error {
107-
return g.sendPacket(g.ctx, packet)
107+
return g.sendPacket(g.ctx, packet, true)
108108
},
109109
},
110110
timeoutManager,
@@ -134,7 +134,7 @@ func (g *GoBackNConn) setN(n uint8) {
134134
s: n + 1,
135135
log: g.log,
136136
sendPkt: func(packet *PacketData) error {
137-
return g.sendPacket(g.ctx, packet)
137+
return g.sendPacket(g.ctx, packet, true)
138138
},
139139
},
140140
g.timeoutManager,
@@ -308,7 +308,9 @@ func (g *GoBackNConn) Close() error {
308308
g.ctx, g.timeoutManager.GetFinSendTimeout(),
309309
)
310310
defer cancel()
311-
if err := g.sendPacket(ctxc, &PacketFIN{}); err != nil {
311+
312+
err := g.sendPacket(ctxc, &PacketFIN{}, false)
313+
if err != nil {
312314
g.log.Errorf("Error sending FIN: %v", err)
313315
}
314316
}
@@ -336,7 +338,9 @@ func (g *GoBackNConn) Close() error {
336338
}
337339

338340
// sendPacket serializes a message and writes it to the underlying send stream.
339-
func (g *GoBackNConn) sendPacket(ctx context.Context, msg Message) error {
341+
func (g *GoBackNConn) sendPacket(ctx context.Context, msg Message,
342+
isResend bool) error {
343+
340344
b, err := msg.Serialize()
341345
if err != nil {
342346
return fmt.Errorf("serialize error: %s", err)
@@ -347,6 +351,9 @@ func (g *GoBackNConn) sendPacket(ctx context.Context, msg Message) error {
347351
return fmt.Errorf("error calling sendToStream: %s", err)
348352
}
349353

354+
// Notify the timeout manager that a message has been sent.
355+
g.timeoutManager.Sent(msg, isResend)
356+
350357
return nil
351358
}
352359

@@ -428,7 +435,7 @@ func (g *GoBackNConn) sendPacketsForever() error {
428435
g.sendQueue.addPacket(packet)
429436

430437
g.log.Tracef("Sending data %d", packet.Seq)
431-
if err := g.sendPacket(g.ctx, packet); err != nil {
438+
if err := g.sendPacket(g.ctx, packet, false); err != nil {
432439
return err
433440
}
434441

@@ -490,6 +497,9 @@ func (g *GoBackNConn) receivePacketsForever() error { // nolint:gocyclo
490497
return fmt.Errorf("deserialize error: %s", err)
491498
}
492499

500+
// Notify the timeout manager that a message has been received.
501+
g.timeoutManager.Received(msg)
502+
493503
// Reset the ping & pong timer if any packet is received.
494504
// If ping/pong is disabled, this is a no-op.
495505
g.pingTicker.Reset()
@@ -514,7 +524,8 @@ func (g *GoBackNConn) receivePacketsForever() error { // nolint:gocyclo
514524
Seq: m.Seq,
515525
}
516526

517-
if err = g.sendPacket(g.ctx, ack); err != nil {
527+
err = g.sendPacket(g.ctx, ack, false)
528+
if err != nil {
518529
return err
519530
}
520531

@@ -573,7 +584,8 @@ func (g *GoBackNConn) receivePacketsForever() error { // nolint:gocyclo
573584
Seq: g.recvSeq,
574585
}
575586

576-
if err = g.sendPacket(g.ctx, nack); err != nil {
587+
err = g.sendPacket(g.ctx, nack, false)
588+
if err != nil {
577589
return err
578590
}
579591

gbn/gbn_server.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ func (g *GoBackNConn) serverHandshake() error { // nolint:gocyclo
8282
}()
8383

8484
var n uint8
85+
var resent bool
8586

8687
for {
8788
g.log.Debugf("Waiting for client SYN")
@@ -131,6 +132,9 @@ func (g *GoBackNConn) serverHandshake() error { // nolint:gocyclo
131132
return err
132133
}
133134

135+
// Notify the timeout manager that we sent a SYN.
136+
g.timeoutManager.Sent(msg, resent)
137+
134138
// Wait for SYNACK
135139
g.log.Debugf("Waiting for client SYNACK")
136140
select {
@@ -146,6 +150,8 @@ func (g *GoBackNConn) serverHandshake() error { // nolint:gocyclo
146150
case <-time.After(g.timeoutManager.GetHandshakeTimeout()):
147151
g.log.Debugf("SYNCACK resendTimeout. Abort and wait " +
148152
"for client to re-initiate")
153+
resent = true
154+
149155
continue
150156
case err := <-errChan:
151157
return err
@@ -163,9 +169,15 @@ func (g *GoBackNConn) serverHandshake() error { // nolint:gocyclo
163169

164170
switch msg.(type) {
165171
case *PacketSYNACK:
172+
// Notify the timeout manager we've received the SYNACK
173+
// response from the counterparty.
174+
g.timeoutManager.Received(msg)
175+
166176
break
167177
case *PacketSYN:
168178
g.log.Debugf("Received SYN. Resend SYN.")
179+
resent = true
180+
169181
goto recvClientSYN
170182
default:
171183
return io.EOF

0 commit comments

Comments
 (0)