Skip to content

Commit d10b72b

Browse files
committed
gbn: make resend timeout dynamic
Prior to this commit, the timeout before a client resends the queue of packets was always a fixed value. This fixed timeout isn't suitable for all clients as the latency for different clients varies. With this commit, we instead set the resend timeout based on how long it took for the other party to respond during the handshake process. The timeout is set to the time it took for the server to respond multiplied by the resendMultiplier, unless the duration is shorter than the default resend timeout. If the the resend timeout has been manually set, the resend timeout will always be set to that value, and won't be dynamically set.
1 parent 09c03b8 commit d10b72b

File tree

6 files changed

+37
-2
lines changed

6 files changed

+37
-2
lines changed

gbn/gbn_client.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ handshake:
108108
return err
109109
}
110110

111+
// Notify the timeout manager that we sent a SYN.
112+
g.timeoutManager.Sent(msg)
113+
111114
for {
112115
// Wait for SYN
113116
log.Debugf("Client waiting for SYN")
@@ -162,6 +165,10 @@ handshake:
162165
return io.EOF
163166
}
164167

168+
// Notify the timeout manager we've received the SYN response from the
169+
// counterparty.
170+
g.timeoutManager.Received(resp)
171+
165172
// Send SYNACK
166173
log.Debugf("Client sending SYNACK")
167174
synack, err := new(PacketSYNACK).Serialize()

gbn/gbn_conn.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,9 @@ func (g *GoBackNConn) sendPacket(ctx context.Context, msg Message) error {
366366
return fmt.Errorf("error calling sendToStream: %s", err)
367367
}
368368

369+
// Notify the timeout manager that a message has been sent.
370+
g.timeoutManager.Sent(msg)
371+
369372
return nil
370373
}
371374

@@ -499,6 +502,9 @@ func (g *GoBackNConn) receivePacketsForever() error { // nolint:gocyclo
499502
return fmt.Errorf("deserialize error: %s", err)
500503
}
501504

505+
// Notify the timeout manager that a message has been received.
506+
g.timeoutManager.Received(msg)
507+
502508
// Reset the ping & pong timer if any packet is received.
503509
// If ping/pong is disabled, this is a no-op.
504510
g.pingTicker.Reset()

gbn/gbn_server.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ func (g *GoBackNConn) serverHandshake() error { // nolint:gocyclo
123123
return err
124124
}
125125

126+
// Notify the timeout manager that we sent a SYN.
127+
g.timeoutManager.Sent(msg)
128+
126129
// Wait for SYNACK
127130
log.Debugf("Waiting for client SYNACK")
128131
select {
@@ -155,6 +158,10 @@ func (g *GoBackNConn) serverHandshake() error { // nolint:gocyclo
155158

156159
switch msg.(type) {
157160
case *PacketSYNACK:
161+
// Notify the timeout manager we've received the SYNACK
162+
// response from the counterparty.
163+
g.timeoutManager.Received(msg)
164+
158165
break
159166
case *PacketSYN:
160167
log.Debugf("Received SYN. Resend SYN.")

gbn/options.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@ func WithTimeout(timeout time.Duration) Option {
2222
}
2323
}
2424

25+
// WithResendMultiplier is used to set the resend multiplier. This is the
26+
// multiplier we use when dynamically setting the resend timeout, based on how
27+
// long it took for other party to respond during the handshake.
28+
// Note that when setting the resend timeout manually with the WithTimeout
29+
// option, this option will have no effect.
30+
func WithResendMultiplier(multiplier int) Option {
31+
return func(conn *GoBackNConn) {
32+
conn.timeoutManager.SetResendMultiplier(multiplier)
33+
}
34+
}
35+
2536
// WithHandshakeTimeout is used to set the timeout used during the handshake.
2637
// If the timeout is reached without response from the peer then the handshake
2738
// will be aborted and restarted.

mailbox/client_conn.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ const (
4545
// to receive ACKS from the peer before resending the queue.
4646
gbnTimeout = 1000 * time.Millisecond
4747

48+
// gbnResendMultiplier is the multiplier that we want the gbn
49+
// connection to use when dynamically setting the resend timeout.
50+
gbnResendMultiplier = 5
51+
4852
// gbnN is the queue size, N, that the gbn server will use. The gbn
4953
// server will send up to N packets before requiring an ACK for the
5054
// first packet in the queue.
@@ -156,7 +160,7 @@ func NewClientConn(ctx context.Context, sid [64]byte, serverHost string,
156160
c := &ClientConn{
157161
transport: transport,
158162
gbnOptions: []gbn.Option{
159-
gbn.WithTimeout(gbnTimeout),
163+
gbn.WithResendMultiplier(gbnResendMultiplier),
160164
gbn.WithHandshakeTimeout(gbnHandshakeTimeout),
161165
gbn.WithKeepalivePing(
162166
gbnClientPingTimeout, gbnPongTimeout,

mailbox/server_conn.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func NewServerConn(ctx context.Context, serverHost string,
7777
cancel: cancel,
7878
quit: make(chan struct{}),
7979
gbnOptions: []gbn.Option{
80-
gbn.WithTimeout(gbnTimeout),
80+
gbn.WithResendMultiplier(gbnResendMultiplier),
8181
gbn.WithHandshakeTimeout(gbnHandshakeTimeout),
8282
gbn.WithKeepalivePing(
8383
gbnServerPingTimeout, gbnPongTimeout,

0 commit comments

Comments
 (0)