socket/dhcp: add retransmission/timeout tests
This commit is contained in:
parent
6768d89165
commit
a43a6772c9
|
@ -545,30 +545,43 @@ mod test {
|
||||||
socket.process(&cx, &ip_repr, &udp_repr, &payload)
|
socket.process(&cx, &ip_repr, &udp_repr, &payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recv<F>(socket: &mut Dhcpv4Socket, timestamp: Instant, mut f: F)
|
fn recv(
|
||||||
where
|
socket: &mut Dhcpv4Socket,
|
||||||
F: FnMut(Result<(Ipv4Repr, UdpRepr, DhcpRepr)>),
|
timestamp: Instant,
|
||||||
{
|
reprs: &[(Ipv4Repr, UdpRepr, DhcpRepr)],
|
||||||
|
) {
|
||||||
let mut cx = Context::DUMMY.clone();
|
let mut cx = Context::DUMMY.clone();
|
||||||
cx.now = timestamp;
|
cx.now = timestamp;
|
||||||
let result = socket.dispatch(&cx, |(mut ip_repr, udp_repr, dhcp_repr)| {
|
|
||||||
assert_eq!(ip_repr.protocol, IpProtocol::Udp);
|
|
||||||
assert_eq!(
|
|
||||||
ip_repr.payload_len,
|
|
||||||
udp_repr.header_len() + dhcp_repr.buffer_len()
|
|
||||||
);
|
|
||||||
|
|
||||||
// We validated the payload len, change it to 0 to make equality testing easier
|
let mut i = 0;
|
||||||
ip_repr.payload_len = 0;
|
|
||||||
|
|
||||||
net_trace!("recv: {:?}", ip_repr);
|
while socket.poll_at(&cx) <= PollAt::Time(timestamp) {
|
||||||
net_trace!(" {:?}", udp_repr);
|
let _ = socket.dispatch(&cx, |(mut ip_repr, udp_repr, dhcp_repr)| {
|
||||||
net_trace!(" {:?}", dhcp_repr);
|
assert_eq!(ip_repr.protocol, IpProtocol::Udp);
|
||||||
Ok(f(Ok((ip_repr, udp_repr, dhcp_repr))))
|
assert_eq!(
|
||||||
});
|
ip_repr.payload_len,
|
||||||
match result {
|
udp_repr.header_len() + dhcp_repr.buffer_len()
|
||||||
Ok(()) => (),
|
);
|
||||||
Err(e) => f(Err(e)),
|
|
||||||
|
// We validated the payload len, change it to 0 to make equality testing easier
|
||||||
|
ip_repr.payload_len = 0;
|
||||||
|
|
||||||
|
net_trace!("recv: {:?}", ip_repr);
|
||||||
|
net_trace!(" {:?}", udp_repr);
|
||||||
|
net_trace!(" {:?}", dhcp_repr);
|
||||||
|
|
||||||
|
let got_repr = (ip_repr, udp_repr, dhcp_repr);
|
||||||
|
match reprs.get(i) {
|
||||||
|
Some(want_repr) => assert_eq!(want_repr, &got_repr),
|
||||||
|
None => panic!("Too many reprs emitted"),
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if i != reprs.len() {
|
||||||
|
panic!("Too few reprs emitted. Wanted {}, got {}", reprs.len(), i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,20 +597,12 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! recv {
|
macro_rules! recv {
|
||||||
($socket:ident, [$( $repr:expr ),*]) => ({
|
($socket:ident, $reprs:expr) => ({
|
||||||
$( recv!($socket, Ok($repr)); )*
|
recv!($socket, time 0, $reprs);
|
||||||
recv!($socket, Err(Error::Exhausted))
|
|
||||||
});
|
});
|
||||||
($socket:ident, time $time:expr, [$( $repr:expr ),*]) => ({
|
($socket:ident, time $time:expr, $reprs:expr) => ({
|
||||||
$( recv!($socket, time $time, Ok($repr)); )*
|
recv(&mut $socket, Instant::from_millis($time), &$reprs);
|
||||||
recv!($socket, time $time, Err(Error::Exhausted))
|
|
||||||
});
|
});
|
||||||
($socket:ident, $result:expr) =>
|
|
||||||
(recv!($socket, time 0, $result));
|
|
||||||
($socket:ident, time $time:expr, $result:expr) =>
|
|
||||||
(recv(&mut $socket, Instant::from_millis($time), |result| {
|
|
||||||
assert_eq!(result, $result)
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "log")]
|
#[cfg(feature = "log")]
|
||||||
|
@ -710,7 +715,7 @@ mod test {
|
||||||
router: Some(SERVER_IP),
|
router: Some(SERVER_IP),
|
||||||
subnet_mask: Some(MASK_24),
|
subnet_mask: Some(MASK_24),
|
||||||
dns_servers: Some(DNS_IPS),
|
dns_servers: Some(DNS_IPS),
|
||||||
lease_duration: Some(60),
|
lease_duration: Some(1000),
|
||||||
|
|
||||||
..DHCP_DEFAULT
|
..DHCP_DEFAULT
|
||||||
};
|
};
|
||||||
|
@ -735,7 +740,7 @@ mod test {
|
||||||
router: Some(SERVER_IP),
|
router: Some(SERVER_IP),
|
||||||
subnet_mask: Some(MASK_24),
|
subnet_mask: Some(MASK_24),
|
||||||
dns_servers: Some(DNS_IPS),
|
dns_servers: Some(DNS_IPS),
|
||||||
lease_duration: Some(60),
|
lease_duration: Some(1000),
|
||||||
|
|
||||||
..DHCP_DEFAULT
|
..DHCP_DEFAULT
|
||||||
};
|
};
|
||||||
|
@ -776,8 +781,8 @@ mod test {
|
||||||
address: SERVER_IP,
|
address: SERVER_IP,
|
||||||
identifier: SERVER_IP,
|
identifier: SERVER_IP,
|
||||||
},
|
},
|
||||||
renew_at: Instant::from_secs(30),
|
renew_at: Instant::from_secs(500),
|
||||||
expires_at: Instant::from_secs(60),
|
expires_at: Instant::from_secs(1000),
|
||||||
});
|
});
|
||||||
|
|
||||||
s
|
s
|
||||||
|
@ -804,43 +809,142 @@ mod test {
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
match s.state {
|
match &s.state {
|
||||||
ClientState::Renewing(r) => {
|
ClientState::Renewing(r) => {
|
||||||
assert_eq!(r.renew_at, Instant::from_secs(30));
|
assert_eq!(r.renew_at, Instant::from_secs(500));
|
||||||
assert_eq!(r.expires_at, Instant::from_secs(60));
|
assert_eq!(r.expires_at, Instant::from_secs(1000));
|
||||||
}
|
}
|
||||||
_ => panic!("Invalid state"),
|
_ => panic!("Invalid state"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_discover_retransmit() {
|
||||||
|
let mut s = socket();
|
||||||
|
|
||||||
|
recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
|
||||||
|
recv!(s, time 1_000, []);
|
||||||
|
recv!(s, time 10_000, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
|
||||||
|
recv!(s, time 11_000, []);
|
||||||
|
recv!(s, time 20_000, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
|
||||||
|
|
||||||
|
// check after retransmits it still works
|
||||||
|
send!(s, time 20_000, (IP_RECV, UDP_RECV, DHCP_OFFER));
|
||||||
|
recv!(s, time 20_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_request_retransmit() {
|
||||||
|
let mut s = socket();
|
||||||
|
|
||||||
|
recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
|
||||||
|
send!(s, time 0, (IP_RECV, UDP_RECV, DHCP_OFFER));
|
||||||
|
recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
|
||||||
|
recv!(s, time 1_000, []);
|
||||||
|
recv!(s, time 5_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
|
||||||
|
recv!(s, time 6_000, []);
|
||||||
|
recv!(s, time 10_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
|
||||||
|
recv!(s, time 15_000, []);
|
||||||
|
recv!(s, time 20_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
|
||||||
|
|
||||||
|
// check after retransmits it still works
|
||||||
|
send!(s, time 20_000, (IP_RECV, UDP_RECV, DHCP_ACK));
|
||||||
|
|
||||||
|
match &s.state {
|
||||||
|
ClientState::Renewing(r) => {
|
||||||
|
assert_eq!(r.renew_at, Instant::from_secs(20 + 500));
|
||||||
|
assert_eq!(r.expires_at, Instant::from_secs(20 + 1000));
|
||||||
|
}
|
||||||
|
_ => panic!("Invalid state"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_request_timeout() {
|
||||||
|
let mut s = socket();
|
||||||
|
|
||||||
|
recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
|
||||||
|
send!(s, time 0, (IP_RECV, UDP_RECV, DHCP_OFFER));
|
||||||
|
recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
|
||||||
|
recv!(s, time 5_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
|
||||||
|
recv!(s, time 10_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
|
||||||
|
recv!(s, time 20_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
|
||||||
|
recv!(s, time 30_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
|
||||||
|
|
||||||
|
// After 5 tries and 70 seconds, it gives up.
|
||||||
|
// 5 + 5 + 10 + 10 + 20 = 70
|
||||||
|
recv!(s, time 70_000, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
|
||||||
|
|
||||||
|
// check it still works
|
||||||
|
send!(s, time 60_000, (IP_RECV, UDP_RECV, DHCP_OFFER));
|
||||||
|
recv!(s, time 60_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_renew() {
|
fn test_renew() {
|
||||||
let mut s = socket_bound();
|
let mut s = socket_bound();
|
||||||
|
|
||||||
recv!(s, []);
|
recv!(s, []);
|
||||||
assert_eq!(s.poll(), None);
|
assert_eq!(s.poll(), None);
|
||||||
recv!(s, time 40_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]);
|
recv!(s, time 500_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]);
|
||||||
assert_eq!(s.poll(), None);
|
assert_eq!(s.poll(), None);
|
||||||
|
|
||||||
match &s.state {
|
match &s.state {
|
||||||
ClientState::Renewing(r) => {
|
ClientState::Renewing(r) => {
|
||||||
// the expiration still hasn't been bumped, because
|
// the expiration still hasn't been bumped, because
|
||||||
// we haven't received the ACK yet
|
// we haven't received the ACK yet
|
||||||
assert_eq!(r.expires_at, Instant::from_secs(60));
|
assert_eq!(r.expires_at, Instant::from_secs(1000));
|
||||||
}
|
}
|
||||||
_ => panic!("Invalid state"),
|
_ => panic!("Invalid state"),
|
||||||
}
|
}
|
||||||
|
|
||||||
send!(s, time 40_000, (IP_RECV, UDP_RECV, DHCP_ACK));
|
send!(s, time 500_000, (IP_RECV, UDP_RECV, DHCP_ACK));
|
||||||
assert_eq!(s.poll(), None);
|
assert_eq!(s.poll(), None);
|
||||||
|
|
||||||
match &s.state {
|
match &s.state {
|
||||||
ClientState::Renewing(r) => {
|
ClientState::Renewing(r) => {
|
||||||
// NOW the expiration gets bumped
|
// NOW the expiration gets bumped
|
||||||
assert_eq!(r.renew_at, Instant::from_secs(40 + 30));
|
assert_eq!(r.renew_at, Instant::from_secs(500 + 500));
|
||||||
assert_eq!(r.expires_at, Instant::from_secs(40 + 60));
|
assert_eq!(r.expires_at, Instant::from_secs(500 + 1000));
|
||||||
}
|
}
|
||||||
_ => panic!("Invalid state"),
|
_ => panic!("Invalid state"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_renew_retransmit() {
|
||||||
|
let mut s = socket_bound();
|
||||||
|
|
||||||
|
recv!(s, []);
|
||||||
|
recv!(s, time 500_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]);
|
||||||
|
recv!(s, time 749_000, []);
|
||||||
|
recv!(s, time 750_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]);
|
||||||
|
recv!(s, time 874_000, []);
|
||||||
|
recv!(s, time 875_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]);
|
||||||
|
|
||||||
|
// check it still works
|
||||||
|
send!(s, time 875_000, (IP_RECV, UDP_RECV, DHCP_ACK));
|
||||||
|
match &s.state {
|
||||||
|
ClientState::Renewing(r) => {
|
||||||
|
// NOW the expiration gets bumped
|
||||||
|
assert_eq!(r.renew_at, Instant::from_secs(875 + 500));
|
||||||
|
assert_eq!(r.expires_at, Instant::from_secs(875 + 1000));
|
||||||
|
}
|
||||||
|
_ => panic!("Invalid state"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_renew_timeout() {
|
||||||
|
let mut s = socket_bound();
|
||||||
|
|
||||||
|
recv!(s, []);
|
||||||
|
recv!(s, time 500_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]);
|
||||||
|
recv!(s, time 999_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]);
|
||||||
|
recv!(s, time 1_000_000, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
|
||||||
|
match &s.state {
|
||||||
|
ClientState::Discovering(_) => {}
|
||||||
|
_ => panic!("Invalid state"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue