Skip to content

Commit d8c9f92

Browse files
authored
Merge pull request #88 from ViktorTigerstrom/2023-11-set-resend-timeout-dynamically
gbn: set resend timeout dynamically
2 parents 24bf8aa + 931a7c3 commit d8c9f92

15 files changed

+1194
-157
lines changed

gbn/config.go

Lines changed: 81 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,82 @@ package gbn
22

33
import "time"
44

5+
// TimeoutOptions can be used to modify the default timeout values used within
6+
// the TimeoutManager.
7+
type TimeoutOptions func(manager *TimeoutManager)
8+
9+
// WithStaticResendTimeout is used to set a static resend timeout. This is the
10+
// time to wait for ACKs before resending the queue.
11+
func WithStaticResendTimeout(timeout time.Duration) TimeoutOptions {
12+
return func(manager *TimeoutManager) {
13+
manager.useStaticTimeout = true
14+
manager.resendTimeout = timeout
15+
}
16+
}
17+
18+
// WithResendMultiplier is used to set the resend multiplier. This is the
19+
// multiplier we use when dynamically setting the resend timeout, based on how
20+
// long it took for other party to respond.
21+
// Note that when setting the resend timeout manually with the
22+
// WithStaticResendTimeout option, this option will have no effect.
23+
// Note that the passed multiplier must be greater than zero or this option will
24+
// have no effect.
25+
func WithResendMultiplier(multiplier int) TimeoutOptions {
26+
return func(manager *TimeoutManager) {
27+
if multiplier > 0 {
28+
manager.resendMultiplier = multiplier
29+
}
30+
}
31+
}
32+
33+
// WithTimeoutUpdateFrequency is used to set the frequency of how many
34+
// corresponding responses we need to receive until updating the resend timeout.
35+
// Note that when setting the resend timeout manually with the WithTimeout
36+
// option, this option will have no effect.
37+
// Also note that the passed frequency must be greater than zero or this option
38+
// will have no effect.
39+
func WithTimeoutUpdateFrequency(frequency int) TimeoutOptions {
40+
return func(manager *TimeoutManager) {
41+
if frequency > 0 {
42+
manager.timeoutUpdateFrequency = frequency
43+
}
44+
}
45+
}
46+
47+
// WithHandshakeTimeout is used to set the timeout used during the handshake.
48+
// If the timeout is reached without response from the peer then the handshake
49+
// will be aborted and restarted.
50+
func WithHandshakeTimeout(timeout time.Duration) TimeoutOptions {
51+
return func(manager *TimeoutManager) {
52+
manager.handshakeTimeout = timeout
53+
}
54+
}
55+
56+
// WithKeepalivePing is used to send a ping packet if no packets have been
57+
// received from the other side for the given duration. This helps keep the
58+
// connection alive and also ensures that the connection is closed if the
59+
// other side does not respond to the ping in a timely manner. After the ping
60+
// the connection will be closed if the other side does not respond within
61+
// time duration.
62+
func WithKeepalivePing(ping, pong time.Duration) TimeoutOptions {
63+
return func(manager *TimeoutManager) {
64+
manager.pingTime = ping
65+
manager.pongTime = pong
66+
}
67+
}
68+
69+
// WithBoostPercent is used to set the boost percent that the timeout manager
70+
// will use to boost the resend timeout & handshake timeout every time a resend
71+
// is required due to not receiving a response within the current timeout.
72+
func WithBoostPercent(boostPercent float32) TimeoutOptions {
73+
return func(manager *TimeoutManager) {
74+
if boostPercent > 0 {
75+
manager.resendBoostPercent = boostPercent
76+
manager.handshakeBoostPercent = boostPercent
77+
}
78+
}
79+
}
80+
581
// config holds the configuration values for an instance of GoBackNConn.
682
type config struct {
783
// n is the window size. The sender can send a maximum of n packets
@@ -26,10 +102,6 @@ type config struct {
26102
// between packets.
27103
maxChunkSize int
28104

29-
// resendTimeout is the duration that will be waited before resending
30-
// the packets in the current queue.
31-
resendTimeout time.Duration
32-
33105
// recvFromStream is the function that will be used to acquire the next
34106
// available packet.
35107
recvFromStream recvBytesFunc
@@ -42,25 +114,17 @@ type config struct {
42114
// been received and processed.
43115
onFIN func()
44116

45-
// handshakeTimeout is the time after which the server or client
46-
// will abort and restart the handshake if the expected response is
47-
// not received from the peer.
48-
handshakeTimeout time.Duration
49-
50-
pingTime time.Duration
51-
pongTime time.Duration
117+
timeoutOptions []TimeoutOptions
52118
}
53119

54120
// newConfig constructs a new config struct.
55121
func newConfig(sendFunc sendBytesFunc, recvFunc recvBytesFunc,
56122
n uint8) *config {
57123

58124
return &config{
59-
n: n,
60-
s: n + 1,
61-
recvFromStream: recvFunc,
62-
sendToStream: sendFunc,
63-
resendTimeout: defaultResendTimeout,
64-
handshakeTimeout: defaultHandshakeTimeout,
125+
n: n,
126+
s: n + 1,
127+
recvFromStream: recvFunc,
128+
sendToStream: sendFunc,
65129
}
66130
}

gbn/gbn_client.go

Lines changed: 12 additions & 1 deletion
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")
@@ -128,11 +132,14 @@ handshake:
128132
default:
129133
}
130134

135+
timeout := g.timeoutManager.GetHandshakeTimeout()
136+
131137
var b []byte
132138
select {
133-
case <-time.After(g.cfg.handshakeTimeout):
139+
case <-time.After(timeout):
134140
g.log.Debugf("SYN resendTimeout. Resending " +
135141
"SYN.")
142+
resent = true
136143

137144
continue handshake
138145
case <-g.quit:
@@ -171,6 +178,10 @@ handshake:
171178
return io.EOF
172179
}
173180

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

0 commit comments

Comments
 (0)