use std::ffi::CStr;
use std::time::{Duration, UNIX_EPOCH, SystemTime};
use crate::addr::ScamperAddr;
use crate::list::{ScamperList, ScamperCycle};
use crate::ffi::scamper_host::{self, ScamperHostT, ScamperHostQueryT, ScamperHostRrT,
ScamperHostRrSoaT, ScamperHostRrMxT, ScamperHostRrTxtT,
ScamperHostRrOptT, ScamperHostRrOptElemT, ScamperHostRrSvcbT, ScamperHostRrSvcbParamT,
SCAMPER_HOST_STOP_NONE, SCAMPER_HOST_STOP_DONE, SCAMPER_HOST_STOP_TIMEOUT,
SCAMPER_HOST_STOP_HALTED, SCAMPER_HOST_STOP_ERROR};
fn timeval_to_duration(tv: *const libc::timeval) -> Option<Duration> {
if tv.is_null() { return None; }
let tv = unsafe { &*tv };
Some(Duration::new(tv.tv_sec as u64, tv.tv_usec as u32 * 1000))
}
fn timeval_to_systemtime(tv: *const libc::timeval) -> Option<SystemTime> {
timeval_to_duration(tv).map(|d| UNIX_EPOCH + d)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HostStopReason {
None, Done, Timeout, Halted, Error, Unknown(u8),
}
impl From<u8> for HostStopReason {
fn from(v: u8) -> Self {
match v {
SCAMPER_HOST_STOP_NONE => Self::None,
SCAMPER_HOST_STOP_DONE => Self::Done,
SCAMPER_HOST_STOP_TIMEOUT => Self::Timeout,
SCAMPER_HOST_STOP_HALTED => Self::Halted,
SCAMPER_HOST_STOP_ERROR => Self::Error,
other => Self::Unknown(other),
}
}
}
pub struct ScamperHostSoa { inner: *mut ScamperHostRrSoaT }
impl ScamperHostSoa {
pub fn mname(&self) -> Option<&str> {
let p = unsafe { scamper_host::scamper_host_rr_soa_mname_get(self.inner) };
if p.is_null() { None } else { Some(unsafe { CStr::from_ptr(p) }.to_str().unwrap_or("")) }
}
pub fn rname(&self) -> Option<&str> {
let p = unsafe { scamper_host::scamper_host_rr_soa_rname_get(self.inner) };
if p.is_null() { None } else { Some(unsafe { CStr::from_ptr(p) }.to_str().unwrap_or("")) }
}
pub fn serial(&self) -> u32 { unsafe { scamper_host::scamper_host_rr_soa_serial_get(self.inner) } }
pub fn refresh(&self) -> u32 { unsafe { scamper_host::scamper_host_rr_soa_refresh_get(self.inner) } }
pub fn retry(&self) -> u32 { unsafe { scamper_host::scamper_host_rr_soa_retry_get(self.inner) } }
pub fn expire(&self) -> u32 { unsafe { scamper_host::scamper_host_rr_soa_expire_get(self.inner) } }
pub fn minimum(&self) -> u32 { unsafe { scamper_host::scamper_host_rr_soa_minimum_get(self.inner) } }
}
impl Drop for ScamperHostSoa {
fn drop(&mut self) { unsafe { scamper_host::scamper_host_rr_soa_free(self.inner) }; }
}
unsafe impl Send for ScamperHostSoa {}
pub struct ScamperHostMx { inner: *mut ScamperHostRrMxT }
impl ScamperHostMx {
pub fn preference(&self) -> u16 { unsafe { scamper_host::scamper_host_rr_mx_preference_get(self.inner) } }
pub fn exchange(&self) -> Option<&str> {
let p = unsafe { scamper_host::scamper_host_rr_mx_exchange_get(self.inner) };
if p.is_null() { None } else { Some(unsafe { CStr::from_ptr(p) }.to_str().unwrap_or("")) }
}
}
impl Drop for ScamperHostMx {
fn drop(&mut self) { unsafe { scamper_host::scamper_host_rr_mx_free(self.inner) }; }
}
unsafe impl Send for ScamperHostMx {}
pub struct ScamperHostTxt { inner: *mut ScamperHostRrTxtT }
impl ScamperHostTxt {
pub fn strc(&self) -> u16 { unsafe { scamper_host::scamper_host_rr_txt_strc_get(self.inner) } }
pub fn str_val(&self, i: u16) -> Option<&str> {
let p = unsafe { scamper_host::scamper_host_rr_txt_str_get(self.inner, i) };
if p.is_null() { None } else { Some(unsafe { CStr::from_ptr(p) }.to_str().unwrap_or("")) }
}
}
impl Drop for ScamperHostTxt {
fn drop(&mut self) { unsafe { scamper_host::scamper_host_rr_txt_free(self.inner) }; }
}
unsafe impl Send for ScamperHostTxt {}
pub struct ScamperHostOptElem { inner: *mut ScamperHostRrOptElemT }
impl ScamperHostOptElem {
pub fn code(&self) -> u16 { unsafe { scamper_host::scamper_host_rr_opt_elem_code_get(self.inner) } }
pub fn len(&self) -> u16 { unsafe { scamper_host::scamper_host_rr_opt_elem_len_get(self.inner) } }
pub fn data(&self) -> &[u8] {
let len = self.len() as usize;
let ptr = unsafe { scamper_host::scamper_host_rr_opt_elem_data_get(self.inner) };
if ptr.is_null() || len == 0 { &[] } else { unsafe { std::slice::from_raw_parts(ptr, len) } }
}
}
impl Drop for ScamperHostOptElem {
fn drop(&mut self) { unsafe { scamper_host::scamper_host_rr_opt_elem_free(self.inner) }; }
}
unsafe impl Send for ScamperHostOptElem {}
pub struct ScamperHostOpt { inner: *mut ScamperHostRrOptT }
impl ScamperHostOpt {
pub fn elemc(&self) -> u16 { unsafe { scamper_host::scamper_host_rr_opt_elemc_get(self.inner) } }
pub fn elem(&self, i: u16) -> Option<ScamperHostOptElem> {
let ptr = unsafe { scamper_host::scamper_host_rr_opt_elem_get(self.inner, i) };
if ptr.is_null() { None } else {
let ptr = unsafe { scamper_host::scamper_host_rr_opt_elem_use(ptr) };
Some(ScamperHostOptElem { inner: ptr })
}
}
}
impl Drop for ScamperHostOpt {
fn drop(&mut self) { unsafe { scamper_host::scamper_host_rr_opt_free(self.inner) }; }
}
unsafe impl Send for ScamperHostOpt {}
pub struct ScamperHostSvcbParam { inner: *mut ScamperHostRrSvcbParamT }
impl ScamperHostSvcbParam {
pub fn key(&self) -> u16 { unsafe { scamper_host::scamper_host_rr_svcb_param_key_get(self.inner) } }
pub fn len(&self) -> u16 { unsafe { scamper_host::scamper_host_rr_svcb_param_len_get(self.inner) } }
pub fn val(&self) -> &[u8] {
let len = self.len() as usize;
let ptr = unsafe { scamper_host::scamper_host_rr_svcb_param_val_get(self.inner) };
if ptr.is_null() || len == 0 { &[] } else { unsafe { std::slice::from_raw_parts(ptr, len) } }
}
}
impl Drop for ScamperHostSvcbParam {
fn drop(&mut self) { unsafe { scamper_host::scamper_host_rr_svcb_param_free(self.inner) }; }
}
unsafe impl Send for ScamperHostSvcbParam {}
pub struct ScamperHostSvcb { inner: *mut ScamperHostRrSvcbT }
impl ScamperHostSvcb {
pub fn target(&self) -> Option<&str> {
let p = unsafe { scamper_host::scamper_host_rr_svcb_target_get(self.inner) };
if p.is_null() { None } else { Some(unsafe { CStr::from_ptr(p) }.to_str().unwrap_or("")) }
}
pub fn priority(&self) -> u16 { unsafe { scamper_host::scamper_host_rr_svcb_priority_get(self.inner) } }
pub fn paramc(&self) -> u16 { unsafe { scamper_host::scamper_host_rr_svcb_paramc_get(self.inner) } }
pub fn param(&self, i: u16) -> Option<ScamperHostSvcbParam> {
let ptr = unsafe { scamper_host::scamper_host_rr_svcb_param_get(self.inner, i) };
if ptr.is_null() { None } else {
let ptr = unsafe { scamper_host::scamper_host_rr_svcb_param_use(ptr) };
Some(ScamperHostSvcbParam { inner: ptr })
}
}
}
impl Drop for ScamperHostSvcb {
fn drop(&mut self) { unsafe { scamper_host::scamper_host_rr_svcb_free(self.inner) }; }
}
unsafe impl Send for ScamperHostSvcb {}
pub struct ScamperHostRr { inner: *mut ScamperHostRrT }
impl ScamperHostRr {
pub(crate) unsafe fn from_ptr(ptr: *mut ScamperHostRrT) -> Option<Self> {
if ptr.is_null() { return None; }
let ptr = unsafe { scamper_host::scamper_host_rr_use(ptr) };
Some(ScamperHostRr { inner: ptr })
}
pub fn rr_class(&self) -> u16 { unsafe { scamper_host::scamper_host_rr_class_get(self.inner) } }
pub fn rr_type(&self) -> u16 { unsafe { scamper_host::scamper_host_rr_type_get(self.inner) } }
pub fn name(&self) -> Option<&str> {
let p = unsafe { scamper_host::scamper_host_rr_name_get(self.inner) };
if p.is_null() { None } else { Some(unsafe { CStr::from_ptr(p) }.to_str().unwrap_or("")) }
}
pub fn ttl(&self) -> u32 { unsafe { scamper_host::scamper_host_rr_ttl_get(self.inner) } }
pub fn addr(&self) -> Option<ScamperAddr> {
let ptr = unsafe { scamper_host::scamper_host_rr_addr_get(self.inner) };
unsafe { ScamperAddr::from_ptr(ptr) }
}
pub fn str_val(&self) -> Option<&str> {
let p = unsafe { scamper_host::scamper_host_rr_str_get(self.inner) };
if p.is_null() { None } else { Some(unsafe { CStr::from_ptr(p) }.to_str().unwrap_or("")) }
}
pub fn soa(&self) -> Option<ScamperHostSoa> {
let ptr = unsafe { scamper_host::scamper_host_rr_soa_get(self.inner) };
if ptr.is_null() { None } else {
let ptr = unsafe { scamper_host::scamper_host_rr_soa_use(ptr) };
Some(ScamperHostSoa { inner: ptr })
}
}
pub fn mx(&self) -> Option<ScamperHostMx> {
let ptr = unsafe { scamper_host::scamper_host_rr_mx_get(self.inner) };
if ptr.is_null() { None } else {
let ptr = unsafe { scamper_host::scamper_host_rr_mx_use(ptr) };
Some(ScamperHostMx { inner: ptr })
}
}
pub fn txt(&self) -> Option<ScamperHostTxt> {
let ptr = unsafe { scamper_host::scamper_host_rr_txt_get(self.inner) };
if ptr.is_null() { None } else {
let ptr = unsafe { scamper_host::scamper_host_rr_txt_use(ptr) };
Some(ScamperHostTxt { inner: ptr })
}
}
pub fn opt(&self) -> Option<ScamperHostOpt> {
let ptr = unsafe { scamper_host::scamper_host_rr_opt_get(self.inner) };
if ptr.is_null() { None } else {
let ptr = unsafe { scamper_host::scamper_host_rr_opt_use(ptr) };
Some(ScamperHostOpt { inner: ptr })
}
}
pub fn svcb(&self) -> Option<ScamperHostSvcb> {
let ptr = unsafe { scamper_host::scamper_host_rr_svcb_get(self.inner) };
if ptr.is_null() { None } else {
let ptr = unsafe { scamper_host::scamper_host_rr_svcb_use(ptr) };
Some(ScamperHostSvcb { inner: ptr })
}
}
}
impl Drop for ScamperHostRr {
fn drop(&mut self) { unsafe { scamper_host::scamper_host_rr_free(self.inner) }; }
}
unsafe impl Send for ScamperHostRr {}
unsafe impl Sync for ScamperHostRr {}
pub struct ScamperHostQuery { inner: *mut ScamperHostQueryT }
impl ScamperHostQuery {
pub(crate) unsafe fn from_ptr(ptr: *mut ScamperHostQueryT) -> Option<Self> {
if ptr.is_null() { return None; }
let ptr = unsafe { scamper_host::scamper_host_query_use(ptr) };
Some(ScamperHostQuery { inner: ptr })
}
pub fn tx(&self) -> Option<SystemTime> {
timeval_to_systemtime(unsafe { scamper_host::scamper_host_query_tx_get(self.inner) })
}
pub fn rx(&self) -> Option<SystemTime> {
timeval_to_systemtime(unsafe { scamper_host::scamper_host_query_rx_get(self.inner) })
}
pub fn rcode(&self) -> u8 { unsafe { scamper_host::scamper_host_query_rcode_get(self.inner) } }
pub fn flags(&self) -> u8 { unsafe { scamper_host::scamper_host_query_flags_get(self.inner) } }
pub fn id(&self) -> u16 { unsafe { scamper_host::scamper_host_query_id_get(self.inner) } }
pub fn ancount(&self) -> u16 { unsafe { scamper_host::scamper_host_query_ancount_get(self.inner) } }
pub fn nscount(&self) -> u16 { unsafe { scamper_host::scamper_host_query_nscount_get(self.inner) } }
pub fn arcount(&self) -> u16 { unsafe { scamper_host::scamper_host_query_arcount_get(self.inner) } }
pub fn an(&self, i: u16) -> Option<ScamperHostRr> {
let ptr = unsafe { scamper_host::scamper_host_query_an_get(self.inner, i) };
unsafe { ScamperHostRr::from_ptr(ptr) }
}
pub fn ns(&self, i: u16) -> Option<ScamperHostRr> {
let ptr = unsafe { scamper_host::scamper_host_query_ns_get(self.inner, i) };
unsafe { ScamperHostRr::from_ptr(ptr) }
}
pub fn ar(&self, i: u16) -> Option<ScamperHostRr> {
let ptr = unsafe { scamper_host::scamper_host_query_ar_get(self.inner, i) };
unsafe { ScamperHostRr::from_ptr(ptr) }
}
pub fn ar_opt(&self) -> Option<ScamperHostRr> {
let ptr = unsafe { scamper_host::scamper_host_query_ar_opt_get(self.inner) };
unsafe { ScamperHostRr::from_ptr(ptr) }
}
}
impl Drop for ScamperHostQuery {
fn drop(&mut self) { unsafe { scamper_host::scamper_host_query_free(self.inner) }; }
}
unsafe impl Send for ScamperHostQuery {}
unsafe impl Sync for ScamperHostQuery {}
pub struct ScamperHost {
pub(crate) inner: *mut ScamperHostT,
}
impl ScamperHost {
pub(crate) unsafe fn from_ptr(ptr: *mut ScamperHostT) -> Option<Self> {
if ptr.is_null() { return None; }
Some(ScamperHost { inner: ptr })
}
pub fn src(&self) -> Option<ScamperAddr> {
let ptr = unsafe { scamper_host::scamper_host_src_get(self.inner) };
unsafe { ScamperAddr::from_ptr(ptr) }
}
pub fn dst(&self) -> Option<ScamperAddr> {
let ptr = unsafe { scamper_host::scamper_host_dst_get(self.inner) };
unsafe { ScamperAddr::from_ptr(ptr) }
}
pub fn userid(&self) -> u32 {
unsafe { scamper_host::scamper_host_userid_get(self.inner) }
}
pub fn start(&self) -> Option<SystemTime> {
timeval_to_systemtime(unsafe { scamper_host::scamper_host_start_get(self.inner) })
}
pub fn qname(&self) -> Option<&str> {
let p = unsafe { scamper_host::scamper_host_qname_get(self.inner) };
if p.is_null() { None } else { Some(unsafe { CStr::from_ptr(p) }.to_str().unwrap_or("")) }
}
pub fn qtype(&self) -> u16 { unsafe { scamper_host::scamper_host_qtype_get(self.inner) } }
pub fn qclass(&self) -> u16 { unsafe { scamper_host::scamper_host_qclass_get(self.inner) } }
pub fn qcount(&self) -> u8 { unsafe { scamper_host::scamper_host_qcount_get(self.inner) } }
pub fn flags(&self) -> u16 { unsafe { scamper_host::scamper_host_flags_get(self.inner) } }
pub fn retries(&self) -> u8 { unsafe { scamper_host::scamper_host_retries_get(self.inner) } }
pub fn stop(&self) -> HostStopReason {
HostStopReason::from(unsafe { scamper_host::scamper_host_stop_get(self.inner) })
}
pub fn ecs(&self) -> Option<&str> {
let p = unsafe { scamper_host::scamper_host_ecs_get(self.inner) };
if p.is_null() { None } else { Some(unsafe { CStr::from_ptr(p) }.to_str().unwrap_or("")) }
}
pub fn errmsg(&self) -> Option<&str> {
let p = unsafe { scamper_host::scamper_host_errmsg_get(self.inner) };
if p.is_null() { None } else { Some(unsafe { CStr::from_ptr(p) }.to_str().unwrap_or("")) }
}
pub fn query(&self, i: u8) -> Option<ScamperHostQuery> {
let ptr = unsafe { scamper_host::scamper_host_query_get(self.inner, i) };
unsafe { ScamperHostQuery::from_ptr(ptr) }
}
pub fn list(&self) -> Option<ScamperList> {
let ptr = unsafe { scamper_host::scamper_host_list_get(self.inner) };
unsafe { ScamperList::from_ptr(ptr) }
}
pub fn cycle(&self) -> Option<ScamperCycle> {
let ptr = unsafe { scamper_host::scamper_host_cycle_get(self.inner) };
unsafe { ScamperCycle::from_ptr(ptr) }
}
pub fn to_json(&self) -> Option<String> {
let mut len = 0usize;
let ptr = unsafe { scamper_host::scamper_host_tojson(self.inner, &mut len) };
if ptr.is_null() { return None; }
let s = unsafe { CStr::from_ptr(ptr) }.to_string_lossy().into_owned();
unsafe { libc::free(ptr as *mut libc::c_void) };
Some(s)
}
}
impl Drop for ScamperHost {
fn drop(&mut self) {
unsafe { scamper_host::scamper_host_free(self.inner) };
}
}
unsafe impl Send for ScamperHost {}
unsafe impl Sync for ScamperHost {}