use crate::{ip::NrfSockAddr, lte_link::LteLink, CancellationToken, Error};
use arrayvec::ArrayString;
use core::net::{IpAddr, SocketAddr};
use core::str::FromStr;
use super::{AddrType, DnsQuery};
pub async fn get_host_by_name(hostname: &str) -> Result<IpAddr, Error> {
resolve_dns(DnsQuery::new(hostname)).await
}
pub async fn get_host_by_name_with_cancellation(
hostname: &str,
token: &CancellationToken,
) -> Result<IpAddr, Error> {
resolve_dns_with_cancellation(DnsQuery::new(hostname), token).await
}
pub async fn resolve_dns(query: DnsQuery<'_>) -> Result<IpAddr, Error> {
resolve_dns_with_cancellation(query, &Default::default()).await
}
pub async fn resolve_dns_with_cancellation(
query: DnsQuery<'_>,
token: &CancellationToken,
) -> Result<IpAddr, Error> {
#[cfg(feature = "defmt")]
defmt::debug!("Resolving dns hostname for \"{}\"", query.hostname());
if let Ok(ip) = query.hostname().parse() {
if !query.addr_type().addr_matches(ip) {
return Err(Error::AddressNotFound);
} else {
return Ok(ip);
}
}
if !query.hostname().is_ascii() {
return Err(Error::HostnameNotAscii);
}
token.bind_to_current_task().await;
let link = LteLink::new().await?;
link.wait_for_link_with_cancellation(token).await?;
let mut found_ip = None;
unsafe {
let hints = nrfxlib_sys::nrf_addrinfo {
ai_family: match query.addr_type() {
AddrType::Any => nrfxlib_sys::NRF_AF_UNSPEC as _,
AddrType::V4 => nrfxlib_sys::NRF_AF_INET as _,
AddrType::V6 => nrfxlib_sys::NRF_AF_INET6 as _,
},
ai_socktype: nrfxlib_sys::NRF_SOCK_STREAM as _,
ai_flags: 0,
ai_protocol: 0,
ai_addrlen: 0,
ai_addr: core::ptr::null_mut(),
ai_canonname: core::ptr::null_mut(),
ai_next: core::ptr::null_mut(),
};
let mut result: *mut nrfxlib_sys::nrf_addrinfo = core::ptr::null_mut();
let mut hostname =
ArrayString::<257>::from_str(query.hostname()).map_err(|_| Error::HostnameTooLong)?;
hostname.push('\0');
let err = nrfxlib_sys::nrf_getaddrinfo(
hostname.as_ptr() as *const core::ffi::c_char,
core::ptr::null(),
&hints as *const _,
&mut result as *mut *mut _,
) as isize;
let deactivation_result = link.deactivate().await;
if err > 0 {
return Err(Error::NrfError(err));
} else if err == -1 {
return Err(Error::NrfError(crate::ffi::get_last_error()));
}
if result.is_null() {
return Err(Error::AddressNotFound);
}
if let Err(deactivation_error) = deactivation_result {
nrfxlib_sys::nrf_freeaddrinfo(result);
return Err(deactivation_error);
}
let mut result_iter = result;
while !result_iter.is_null() && found_ip.is_none() {
let address = (*result_iter).ai_addr;
if (*address).sa_family == nrfxlib_sys::NRF_AF_INET as u16 {
let dns_addr: &nrfxlib_sys::nrf_sockaddr_in =
&*(address as *const nrfxlib_sys::nrf_sockaddr_in);
let socket_addr: SocketAddr = NrfSockAddr::from(*dns_addr).into();
found_ip = Some(socket_addr.ip());
} else if (*address).sa_family == nrfxlib_sys::NRF_AF_INET6 as u16 {
let dns_addr: &nrfxlib_sys::nrf_sockaddr_in6 =
&*(address as *const nrfxlib_sys::nrf_sockaddr_in6);
let socket_addr: SocketAddr = NrfSockAddr::from(*dns_addr).into();
found_ip = Some(socket_addr.ip());
}
result_iter = (*result_iter).ai_next;
}
nrfxlib_sys::nrf_freeaddrinfo(result);
if let Some(found_ip) = found_ip {
Ok(found_ip)
} else {
Err(Error::AddressNotFound)
}
}
}