use std::{
io,
os::raw::{
c_char,
c_void,
},
pin::Pin,
task::{
Context,
Poll,
},
};
use crate::{
cstr,
dns_consts::{
Class,
Type,
},
ffi,
inner,
interface::Interface,
};
type CallbackStream = crate::stream::ServiceStream<inner::OwnedService, QueryRecordResult>;
bitflags::bitflags! {
#[derive(Default)]
pub struct QueryRecordFlags: ffi::DNSServiceFlags {
const LONG_LIVED_QUERY = ffi::FLAGS_LONG_LIVED_QUERY;
}
}
bitflags::bitflags! {
#[derive(Default)]
pub struct QueriedRecordFlags: ffi::DNSServiceFlags {
const MORE_COMING = ffi::FLAGS_MORE_COMING;
const ADD = ffi::FLAGS_ADD;
}
}
#[must_use = "streams do nothing unless polled"]
pub struct QueryRecord {
stream: crate::fused_err_stream::FusedErrorStream<CallbackStream>,
}
impl QueryRecord {
pin_utils::unsafe_pinned!(stream: crate::fused_err_stream::FusedErrorStream<CallbackStream>);
}
impl futures_core::Stream for QueryRecord {
type Item = io::Result<QueryRecordResult>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.stream().poll_next(cx)
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct QueryRecordResult {
pub flags: QueriedRecordFlags,
pub interface: Interface,
pub fullname: String,
pub rr_type: Type,
pub rr_class: Class,
pub rdata: Vec<u8>,
pub ttl: u32,
}
unsafe extern "C" fn query_record_callback(
_sd_ref: ffi::DNSServiceRef,
flags: ffi::DNSServiceFlags,
interface_index: u32,
error_code: ffi::DNSServiceErrorType,
fullname: *const c_char,
rr_type: u16,
rr_class: u16,
rd_len: u16,
rdata: *const u8,
ttl: u32,
context: *mut c_void,
) {
CallbackStream::run_callback(context, error_code, || {
let fullname = cstr::from_cstr(fullname)?;
let rdata = ::std::slice::from_raw_parts(rdata, rd_len as usize);
Ok(QueryRecordResult {
flags: QueriedRecordFlags::from_bits_truncate(flags),
interface: Interface::from_raw(interface_index),
fullname: fullname.to_string(),
rr_type: Type(rr_type),
rr_class: Class(rr_class),
rdata: rdata.into(),
ttl,
})
});
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct QueryRecordData {
pub flags: QueryRecordFlags,
pub interface: Interface,
pub rr_class: Class,
#[doc(hidden)]
pub _non_exhaustive: crate::non_exhaustive_struct::NonExhaustiveMarker,
}
impl Default for QueryRecordData {
fn default() -> Self {
Self {
flags: QueryRecordFlags::default(),
interface: Interface::default(),
rr_class: Class::IN,
_non_exhaustive: crate::non_exhaustive_struct::NonExhaustiveMarker,
}
}
}
fn _query_record_extended(
fullname: &str,
rr_type: Type,
data: QueryRecordData,
) -> io::Result<QueryRecord> {
crate::init();
let fullname = cstr::CStr::from(&fullname)?;
let stream = CallbackStream::new(move |sender| {
inner::OwnedService::query_record(
data.flags.bits(),
data.interface.into_raw(),
&fullname,
rr_type,
data.rr_class,
Some(query_record_callback),
sender,
)
})
.into();
Ok(QueryRecord { stream })
}
#[doc(alias = "DNSServiceQueryRecord")]
pub fn query_record_extended(fullname: &str, rr_type: Type, data: QueryRecordData) -> QueryRecord {
match _query_record_extended(fullname, rr_type, data) {
Ok(qr) => qr,
Err(e) => QueryRecord {
stream: Err(e).into(),
},
}
}
#[doc(alias = "DNSServiceQueryRecord")]
pub fn query_record(fullname: &str, rr_type: Type) -> QueryRecord {
query_record_extended(fullname, rr_type, QueryRecordData::default())
}