Skip to content

Commit

Permalink
Merge pull request #88 from ViktorTigerstrom/2023-11-set-resend-timeo…
Browse files Browse the repository at this point in the history
…ut-dynamically

gbn: set resend timeout dynamically
  • Loading branch information
ellemouton authored Jan 18, 2024
2 parents 24bf8aa + 931a7c3 commit d8c9f92
Show file tree
Hide file tree
Showing 15 changed files with 1,194 additions and 157 deletions.
98 changes: 81 additions & 17 deletions gbn/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,82 @@ package gbn

import "time"

// TimeoutOptions can be used to modify the default timeout values used within
// the TimeoutManager.
type TimeoutOptions func(manager *TimeoutManager)

// WithStaticResendTimeout is used to set a static resend timeout. This is the
// time to wait for ACKs before resending the queue.
func WithStaticResendTimeout(timeout time.Duration) TimeoutOptions {
return func(manager *TimeoutManager) {
manager.useStaticTimeout = true
manager.resendTimeout = timeout
}
}

// WithResendMultiplier is used to set the resend multiplier. This is the
// multiplier we use when dynamically setting the resend timeout, based on how
// long it took for other party to respond.
// Note that when setting the resend timeout manually with the
// WithStaticResendTimeout option, this option will have no effect.
// Note that the passed multiplier must be greater than zero or this option will
// have no effect.
func WithResendMultiplier(multiplier int) TimeoutOptions {
return func(manager *TimeoutManager) {
if multiplier > 0 {
manager.resendMultiplier = multiplier
}
}
}

// WithTimeoutUpdateFrequency is used to set the frequency of how many
// corresponding responses we need to receive until updating the resend timeout.
// Note that when setting the resend timeout manually with the WithTimeout
// option, this option will have no effect.
// Also note that the passed frequency must be greater than zero or this option
// will have no effect.
func WithTimeoutUpdateFrequency(frequency int) TimeoutOptions {
return func(manager *TimeoutManager) {
if frequency > 0 {
manager.timeoutUpdateFrequency = frequency
}
}
}

// WithHandshakeTimeout is used to set the timeout used during the handshake.
// If the timeout is reached without response from the peer then the handshake
// will be aborted and restarted.
func WithHandshakeTimeout(timeout time.Duration) TimeoutOptions {
return func(manager *TimeoutManager) {
manager.handshakeTimeout = timeout
}
}

// WithKeepalivePing is used to send a ping packet if no packets have been
// received from the other side for the given duration. This helps keep the
// connection alive and also ensures that the connection is closed if the
// other side does not respond to the ping in a timely manner. After the ping
// the connection will be closed if the other side does not respond within
// time duration.
func WithKeepalivePing(ping, pong time.Duration) TimeoutOptions {
return func(manager *TimeoutManager) {
manager.pingTime = ping
manager.pongTime = pong
}
}

// WithBoostPercent is used to set the boost percent that the timeout manager
// will use to boost the resend timeout & handshake timeout every time a resend
// is required due to not receiving a response within the current timeout.
func WithBoostPercent(boostPercent float32) TimeoutOptions {
return func(manager *TimeoutManager) {
if boostPercent > 0 {
manager.resendBoostPercent = boostPercent
manager.handshakeBoostPercent = boostPercent
}
}
}

// config holds the configuration values for an instance of GoBackNConn.
type config struct {
// n is the window size. The sender can send a maximum of n packets
Expand All @@ -26,10 +102,6 @@ type config struct {
// between packets.
maxChunkSize int

// resendTimeout is the duration that will be waited before resending
// the packets in the current queue.
resendTimeout time.Duration

// recvFromStream is the function that will be used to acquire the next
// available packet.
recvFromStream recvBytesFunc
Expand All @@ -42,25 +114,17 @@ type config struct {
// been received and processed.
onFIN func()

// handshakeTimeout is the time after which the server or client
// will abort and restart the handshake if the expected response is
// not received from the peer.
handshakeTimeout time.Duration

pingTime time.Duration
pongTime time.Duration
timeoutOptions []TimeoutOptions
}

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

return &config{
n: n,
s: n + 1,
recvFromStream: recvFunc,
sendToStream: sendFunc,
resendTimeout: defaultResendTimeout,
handshakeTimeout: defaultHandshakeTimeout,
n: n,
s: n + 1,
recvFromStream: recvFunc,
sendToStream: sendFunc,
}
}
13 changes: 12 additions & 1 deletion gbn/gbn_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ func (g *GoBackNConn) clientHandshake() error {
var (
resp Message
respSYN *PacketSYN
resent bool
)
handshake:
for {
Expand All @@ -115,6 +116,9 @@ handshake:
return err
}

// Notify the timeout manager that we sent a SYN.
g.timeoutManager.Sent(msg, resent)

for {
// Wait for SYN
g.log.Debugf("Waiting for SYN")
Expand All @@ -128,11 +132,14 @@ handshake:
default:
}

timeout := g.timeoutManager.GetHandshakeTimeout()

var b []byte
select {
case <-time.After(g.cfg.handshakeTimeout):
case <-time.After(timeout):
g.log.Debugf("SYN resendTimeout. Resending " +
"SYN.")
resent = true

continue handshake
case <-g.quit:
Expand Down Expand Up @@ -171,6 +178,10 @@ handshake:
return io.EOF
}

// Notify the timeout manager we've received the SYN response from the
// counterparty.
g.timeoutManager.Received(resp)

// Send SYNACK
g.log.Debugf("Sending SYNACK")
synack, err := new(PacketSYNACK).Serialize()
Expand Down
Loading

0 comments on commit d8c9f92

Please sign in to comment.