use futures::{
self,
Async,
};
use std::{
io,
os::raw::{
c_char,
c_void,
},
};
use tokio_core::reactor::{
Handle,
Remote,
};
use cstr;
use dns_consts::Type;
use evented::EventedDNSService;
use ffi;
use interface::Interface;
use raw;
use remote::GetRemote;
type CallbackFuture = ::future::ServiceFuture<RegisterResult>;
bitflags! {
#[derive(Default)]
pub struct RegisterFlags: ffi::DNSServiceFlags {
const NO_AUTO_RENAME = ffi::FLAGS_NO_AUTO_RENAME;
const SHARED = ffi::FLAGS_SHARED;
const UNIQUE = ffi::FLAGS_UNIQUE;
}
}
pub struct Registration(EventedDNSService);
impl Registration {
pub fn add_record(
&self,
rr_type: Type,
rdata: &[u8],
ttl: u32,
) -> io::Result<::Record> {
Ok(self
.0
.service()
.add_record(0 , rr_type, rdata, ttl)?
.into())
}
pub fn get_default_txt_record(&self) -> ::Record {
self.0.service().get_default_txt_record().into()
}
}
#[must_use = "futures do nothing unless polled"]
pub struct Register(CallbackFuture);
impl Register {
pub fn add_record(
&self,
rr_type: Type,
rdata: &[u8],
ttl: u32,
) -> io::Result<::Record> {
Ok(self
.0
.service()
.add_record(0 , rr_type, rdata, ttl)?
.into())
}
pub fn get_default_txt_record(&self) -> ::Record {
self.0.service().get_default_txt_record().into()
}
}
impl futures::Future for Register {
type Error = io::Error;
type Item = (Registration, RegisterResult);
fn poll(&mut self) -> Result<Async<Self::Item>, Self::Error> {
match self.0.poll() {
Ok(Async::Ready((service, item))) => {
Ok(Async::Ready((Registration(service), item)))
},
Ok(Async::NotReady) => Ok(Async::NotReady),
Err(e) => Err(e),
}
}
}
impl GetRemote for Register {
fn remote(&self) -> &Remote {
self.0.remote()
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct RegisterResult {
pub name: String,
pub reg_type: String,
pub domain: String,
}
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 = unsafe { cstr::from_cstr(name) }?;
let reg_type = unsafe { cstr::from_cstr(reg_type) }?;
let domain = unsafe { 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],
}
impl<'a> Default for RegisterData<'a> {
fn default() -> Self {
RegisterData {
flags: RegisterFlags::default(),
interface: Interface::default(),
name: None,
domain: None,
host: None,
txt: b"",
}
}
}
#[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
pub fn register_extended(
reg_type: &str,
port: u16,
data: RegisterData,
handle: &Handle,
) -> io::Result<Register> {
::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)?;
Ok(Register(CallbackFuture::new(handle, move |sender| {
raw::DNSService::register(
data.flags.bits(),
data.interface.into_raw(),
&name,
®_type,
&domain,
&host,
port.to_be(),
data.txt,
Some(register_callback),
sender,
)
})?))
}
#[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
pub fn register(
reg_type: &str,
port: u16,
handle: &Handle,
) -> io::Result<Register> {
register_extended(reg_type, port, RegisterData::default(), handle)
}