use std::time::Duration;
use super::{
msg::{DhcpV4Message, DhcpV4MessageType},
DhcpV4Socket, DhcpV4State,
};
use crate::{DhcpError, DhcpV4Client};
impl DhcpV4Client {
pub(crate) async fn request(&mut self) -> Result<(), DhcpError> {
loop {
let max_wait_time = self.requset_max_wait_time();
match tokio::time::timeout(max_wait_time, self._request()).await {
Ok(Ok(())) => return Ok(()),
Ok(Err(e)) => {
log::info!(
"Retrying on error {e} after {} seconds",
max_wait_time.as_secs()
);
tokio::time::sleep(max_wait_time).await;
}
Err(_) => {
log::info!(
"Timeout({}s) on waiting DHCP server DHCPACK reply \
for DHCPREQUEST, retrying",
max_wait_time.as_secs(),
);
self.retry_count += 1;
}
}
}
}
fn requset_max_wait_time(&self) -> Duration {
self.discovery_max_wait_time()
}
async fn _request(&mut self) -> Result<(), DhcpError> {
let lease = match self.pending_lease.as_ref() {
Some(l) => l,
None => {
log::error!(
"BUG: Got empty lease but in DhcpV4State::Selecting, \
rollback to DhcpV4State::InitReboot"
);
self.state = DhcpV4State::InitReboot;
return Ok(());
}
};
let dhcp_msg =
DhcpV4Message::new_request(self.xid, &self.config, lease);
let xid = self.xid;
let raw_socket = self.get_raw_socket_or_init().await?;
log::debug!("Sending DHCPREQUEST");
raw_socket
.send(&dhcp_msg.to_eth_packet_broadcast()?)
.await?;
log::debug!("Waiting DHCP server reply with DHCPACK");
loop {
match raw_socket
.recv_dhcp_lease(DhcpV4MessageType::Ack, xid)
.await
{
Ok(Some(l)) => {
self.done(l)?;
return Ok(());
}
Ok(None) => (),
Err(e) => {
log::info!("Ignoring invalid DHCP package: {e}");
}
};
}
}
}