use std::{
future::Future,
io,
os::raw::{
c_char,
c_void,
},
pin::Pin,
task::{
Context,
Poll,
},
};
use crate::{
cstr,
dns_consts::Type,
ffi,
inner,
interface::Interface,
};
type CallbackFuture = crate::future::ServiceFuture<inner::SharedService, RegisterResult>;
bitflags::bitflags! {
#[derive(Default)]
pub struct RegisterFlags: crate::ffi::DNSServiceFlags {
const NO_AUTO_RENAME = crate::ffi::FLAGS_NO_AUTO_RENAME;
const SHARED = ffi::FLAGS_SHARED;
const UNIQUE = ffi::FLAGS_UNIQUE;
}
}
pub struct Registration(inner::SharedService);
impl Registration {
#[doc(alias = "DNSServiceAddRecord")]
pub fn add_record(&self, rr_type: Type, rdata: &[u8], ttl: u32) -> io::Result<crate::Record> {
Ok(self
.0
.clone()
.add_record(0 , rr_type, rdata, ttl)?
.into())
}
pub fn get_default_txt_record(&self) -> crate::Record {
self.0.clone().get_default_txt_record().into()
}
}
#[must_use = "futures do nothing unless polled"]
pub struct Register {
future: CallbackFuture,
}
impl Register {
pin_utils::unsafe_pinned!(future: CallbackFuture);
#[doc(alias = "DNSServiceAddRecord")]
pub fn add_record(&self, rr_type: Type, rdata: &[u8], ttl: u32) -> io::Result<crate::Record> {
Ok(self
.future
.service()
.clone()
.add_record(0 , rr_type, rdata, ttl)?
.into())
}
pub fn get_default_txt_record(&self) -> crate::Record {
self.future
.service()
.clone()
.get_default_txt_record()
.into()
}
}
impl Future for Register {
type Output = io::Result<(Registration, RegisterResult)>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let (service, item) = futures_core::ready!(self.future().poll(cx))?;
Poll::Ready(Ok((Registration(service), item)))
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct RegisterResult {
pub name: String,
pub reg_type: String,
pub domain: String,
}
unsafe extern "C" fn register_callback(
_sd_ref: ffi::DNSServiceRef,
_flags: ffi::DNSServiceFlags,
error_code: ffi::DNSServiceErrorType,
name: *const c_char,
reg_type: *const c_char,
domain: *const c_char,
context: *mut c_void,
) {
CallbackFuture::run_callback(context, error_code, || {
let name = cstr::from_cstr(name)?;
let reg_type = cstr::from_cstr(reg_type)?;
let domain = cstr::from_cstr(domain)?;
Ok(RegisterResult {
name: name.to_string(),
reg_type: reg_type.to_string(),
domain: domain.to_string(),
})
});
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct RegisterData<'a> {
pub flags: RegisterFlags,
pub interface: Interface,
pub name: Option<&'a str>,
pub domain: Option<&'a str>,
pub host: Option<&'a str>,
pub txt: &'a [u8],
#[doc(hidden)]
pub _non_exhaustive: crate::non_exhaustive_struct::NonExhaustiveMarker,
}
impl<'a> Default for RegisterData<'a> {
fn default() -> Self {
Self {
flags: RegisterFlags::default(),
interface: Interface::default(),
name: None,
domain: None,
host: None,
txt: b"",
_non_exhaustive: crate::non_exhaustive_struct::NonExhaustiveMarker,
}
}
}
#[doc(alias = "DNSServiceRegister")]
#[allow(clippy::too_many_arguments)]
pub fn register_extended(
reg_type: &str,
port: u16,
data: RegisterData<'_>,
) -> io::Result<Register> {
crate::init();
let name = cstr::NullableCStr::from(&data.name)?;
let reg_type = cstr::CStr::from(®_type)?;
let domain = cstr::NullableCStr::from(&data.domain)?;
let host = cstr::NullableCStr::from(&data.host)?;
let future = CallbackFuture::new(move |sender| {
inner::OwnedService::register(
data.flags.bits(),
data.interface.into_raw(),
&name,
®_type,
&domain,
&host,
port.to_be(),
data.txt,
Some(register_callback),
sender,
)
.map(|s| s.share())
})?;
Ok(Register { future })
}
#[doc(alias = "DNSServiceRegister")]
#[allow(clippy::too_many_arguments)]
pub fn register(reg_type: &str, port: u16) -> io::Result<Register> {
register_extended(reg_type, port, RegisterData::default())
}