@@ -10,6 +10,7 @@ const (
1010 defaultHandshakeTimeout = 100 * time .Millisecond
1111 defaultResendTimeout = 100 * time .Millisecond
1212 finSendTimeout = 1000 * time .Millisecond
13+ defaultResendMultiplier = 5
1314 DefaultSendTimeout = math .MaxInt64
1415 DefaultRecvTimeout = math .MaxInt64
1516)
@@ -19,6 +20,10 @@ type TimeoutManager struct {
1920 // by the server or the client.
2021 isServer bool
2122
23+ // useStaticTimeout is used to indicate whether the resendTimeout
24+ // has been manually set, and if so, should not be updated dynamically.
25+ useStaticTimeout bool
26+
2227 // resendTimeout defines the current resend timeout used by the
2328 // timeout manager.
2429 // The resend timeout is the duration that will be waited before
@@ -29,6 +34,12 @@ type TimeoutManager struct {
2934 resendTimeout time.Duration
3035 resendTimeoutMu sync.RWMutex
3136
37+ // resendMultiplier defines the multiplier used when multiplying the
38+ // duration it took for the other party to respond when setting the
39+ // resendTimeout dynamically during the handshake.
40+ resendMultiplier int
41+ resendMultiplierMu sync.RWMutex
42+
3243 // latestSentSYNTime is used to keep track of the time when the latest
3344 // SYN message was sent. This is used to dynamically set the resend
3445 // timeout, based on how long it took for the other party to respond to
@@ -62,11 +73,76 @@ func NewTimeOutManager(isServer bool) *TimeoutManager {
6273 isServer : isServer ,
6374 resendTimeout : defaultResendTimeout ,
6475 handshakeTimeout : defaultHandshakeTimeout ,
76+ useStaticTimeout : false ,
77+ resendMultiplier : defaultResendMultiplier ,
6578 recvTimeout : DefaultRecvTimeout ,
6679 sendTimeout : DefaultSendTimeout ,
6780 }
6881}
6982
83+ // Sent is should be called when a message is sent by the connection.
84+ func (m * TimeoutManager ) Sent (msg Message ) {
85+ //nolint:godox
86+ // TODO(viktor): In the future, we may want to use this to keep track of
87+ // the time it took for the other party to respond to other types of
88+ // messages than the handshake, and dynamically keep updating the resend
89+ // timeout to ensure that it reflects the current response time.
90+ switch msg .(type ) { //nolint:gocritic
91+ case * PacketSYN :
92+ // Note that we may send multiple SYN messages before receiving
93+ // a response. Therefore, this field might be updated multiple
94+ // times.
95+ m .latestSentSYNTime = time .Now ()
96+ }
97+ }
98+
99+ // Received is should be called when a message is received by the connection.
100+ func (m * TimeoutManager ) Received (msg Message ) {
101+ //nolint:godox
102+ // TODO(viktor): In the future, we may want to use this to keep track of
103+ // the time it took for the other party to respond to other types of
104+ // messages than the handshake, and dynamically keep updating the resend
105+ // timeout to ensure that it reflects the current response time.
106+ switch msg .(type ) {
107+ case * PacketSYN :
108+ if ! m .isServer {
109+ m .updateResendTimeout (time .Since (m .latestSentSYNTime ))
110+ }
111+
112+ case * PacketSYNACK :
113+ if m .isServer {
114+ m .updateResendTimeout (time .Since (m .latestSentSYNTime ))
115+ }
116+ }
117+ }
118+
119+ // updateResendTimeout updates the resend timeout based on the given response
120+ // time. The resend timeout will be only be updated if the given response time
121+ // is greater than the default resend timeout, after being multiplied by the
122+ // resendMultiplier.
123+ // If a static timeout has been manually set, then this function will do be a
124+ // no-op.
125+ func (m * TimeoutManager ) updateResendTimeout (responseTime time.Duration ) {
126+ if m .useStaticTimeout {
127+ log .Tracef ("Not increasing resendTimeout as it has been set " +
128+ "manually" )
129+
130+ return
131+ }
132+
133+ multipliedTimeout := time .Duration (m .resendMultiplier ) * responseTime
134+
135+ if multipliedTimeout > defaultResendTimeout {
136+ log .Tracef ("Updating resendTimeout to %v" , multipliedTimeout )
137+
138+ m .resendTimeout = multipliedTimeout
139+ } else {
140+ log .Tracef ("Not updating resendTimeout to %v as it is not " +
141+ "greater than the minimum resendTimeout which is %v" ,
142+ multipliedTimeout , m .resendTimeout )
143+ }
144+ }
145+
70146// GetResendTimeout returns the current resend timeout.
71147func (m * TimeoutManager ) GetResendTimeout () time.Duration {
72148 m .resendTimeoutMu .RLock ()
@@ -107,14 +183,24 @@ func (m *TimeoutManager) GetRecvTimeout() time.Duration {
107183 return m .recvTimeout
108184}
109185
110- // SetResendTimeout sets the resend timeout to the given value, and also
186+ // SetStaticResendTimeout sets the resend timeout to the given value, and also
111187// marks the timeout manager as using a static resend timeout, which will mean
112188// that the resend timeout will not be updated dynamically.
113- func (m * TimeoutManager ) SetResendTimeout (resendTimeout time.Duration ) {
189+ func (m * TimeoutManager ) SetStaticResendTimeout (resendTimeout time.Duration ) {
114190 m .resendTimeoutMu .Lock ()
115191 defer m .resendTimeoutMu .Unlock ()
116192
117193 m .resendTimeout = resendTimeout
194+ m .useStaticTimeout = true
195+ }
196+
197+ // SetResendMultiplier sets the resend multiplier used when dynamically
198+ // setting the resend timeout.
199+ func (m * TimeoutManager ) SetResendMultiplier (resendMultiplier int ) {
200+ m .resendMultiplierMu .Lock ()
201+ defer m .resendMultiplierMu .Unlock ()
202+
203+ m .resendMultiplier = resendMultiplier
118204}
119205
120206// SetHandshakeTimeout sets the handshake timeout.
0 commit comments