Skip to content

Commit 3755e86

Browse files
committed
Add max_renew_timeout field to DHCP RetryConfig struct
1 parent 01e1acb commit 3755e86

File tree

2 files changed

+50
-2
lines changed

2 files changed

+50
-2
lines changed

src/socket/dhcpv4.rs

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,17 @@ enum ClientState {
114114
/// Timeout and retry configuration.
115115
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
116116
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
117+
#[non_exhaustive]
117118
pub struct RetryConfig {
118119
pub discover_timeout: Duration,
119120
/// The REQUEST timeout doubles every 2 tries.
120121
pub initial_request_timeout: Duration,
121122
pub request_retries: u16,
122123
pub min_renew_timeout: Duration,
124+
/// An upper bound on how long to wait between retrying a renew or rebind.
125+
///
126+
/// Set this to [`Duration::MAX`] if you don't want to impose an upper bound.
127+
pub max_renew_timeout: Duration,
123128
}
124129

125130
impl Default for RetryConfig {
@@ -129,6 +134,7 @@ impl Default for RetryConfig {
129134
initial_request_timeout: Duration::from_secs(5),
130135
request_retries: 5,
131136
min_renew_timeout: Duration::from_secs(60),
137+
max_renew_timeout: Duration::MAX,
132138
}
133139
}
134140
}
@@ -214,6 +220,11 @@ impl<'a> Socket<'a> {
214220
self.retry_config = config;
215221
}
216222

223+
/// Gets the current retry/timeouts configuration
224+
pub fn get_retry_config(&self) -> RetryConfig {
225+
self.retry_config
226+
}
227+
217228
/// Set the outgoing options.
218229
pub fn set_outgoing_options(&mut self, options: &'a [DhcpOption<'a>]) {
219230
self.outgoing_options = options;
@@ -682,14 +693,16 @@ impl<'a> Socket<'a> {
682693
+ self
683694
.retry_config
684695
.min_renew_timeout
685-
.max((state.expires_at - now) / 2);
696+
.max((state.expires_at - now) / 2)
697+
.min(self.retry_config.max_renew_timeout);
686698
} else {
687699
state.renew_at = now
688700
+ self
689701
.retry_config
690702
.min_renew_timeout
691703
.max((state.rebind_at - now) / 2)
692-
.min(state.rebind_at - now);
704+
.min(state.rebind_at - now)
705+
.min(self.retry_config.max_renew_timeout);
693706
}
694707

695708
self.transaction_id = next_transaction_id;
@@ -1358,6 +1371,39 @@ mod test {
13581371
}
13591372
}
13601373

1374+
#[rstest]
1375+
#[case::ip(Medium::Ethernet)]
1376+
#[cfg(feature = "medium-ethernet")]
1377+
fn test_min_max_renew_timeout(#[case] medium: Medium) {
1378+
let mut s = socket_bound(medium);
1379+
// Set a minimum of 45s and a maximum of 120s
1380+
let config = RetryConfig {
1381+
max_renew_timeout: Duration::from_secs(120),
1382+
min_renew_timeout: Duration::from_secs(45),
1383+
..s.get_retry_config()
1384+
};
1385+
s.set_retry_config(config);
1386+
recv!(s, []);
1387+
// First renew attempt at T1
1388+
recv!(s, time 499_999, []);
1389+
recv!(s, time 500_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]);
1390+
// Next renew attempt 120s after T1 because we hit the max
1391+
recv!(s, time 619_999, []);
1392+
recv!(s, time 620_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]);
1393+
// Next renew attempt 120s after previous because we hit the max again
1394+
recv!(s, time 739_999, []);
1395+
recv!(s, time 740_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]);
1396+
// Next renew attempt half way to T2
1397+
recv!(s, time 807_499, []);
1398+
recv!(s, time 807_500, [(IP_SEND, UDP_SEND, DHCP_RENEW)]);
1399+
// Next renew attempt 45s after previous because we hit the min
1400+
recv!(s, time 852_499, []);
1401+
recv!(s, time 852_500, [(IP_SEND, UDP_SEND, DHCP_RENEW)]);
1402+
// Next is a rebind, because the min puts us after T2
1403+
recv!(s, time 874_999, []);
1404+
recv!(s, time 875_000, [(IP_BROADCAST_ADDRESSED, UDP_SEND, DHCP_REBIND)]);
1405+
}
1406+
13611407
#[rstest]
13621408
#[case::ip(Medium::Ethernet)]
13631409
#[cfg(feature = "medium-ethernet")]

src/time.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ pub struct Duration {
184184

185185
impl Duration {
186186
pub const ZERO: Duration = Duration::from_micros(0);
187+
/// The longest possible duration we can encode.
188+
pub const MAX: Duration = Duration::from_micros(u64::MAX);
187189
/// Create a new `Duration` from a number of microseconds.
188190
pub const fn from_micros(micros: u64) -> Duration {
189191
Duration { micros }

0 commit comments

Comments
 (0)