use futures::{
self,
Async,
Future,
};
use std::{
io,
os::raw::c_void,
rc::Rc,
};
use tokio_core::reactor::{
Handle,
Remote,
};
use cstr;
use dns_consts::{
Class,
Type,
};
use evented::EventedDNSService;
use ffi;
use interface::Interface;
use raw;
use remote::GetRemote;
type CallbackFuture = ::future::ServiceFutureSingle<RegisterRecordResult>;
pub struct Connection(Rc<EventedDNSService>);
impl GetRemote for Connection {
fn remote(&self) -> &Remote {
self.0.remote()
}
}
pub fn connect(handle: &Handle) -> io::Result<Connection> {
::init();
let con = raw::DNSService::create_connection()?;
Ok(Connection(Rc::new(EventedDNSService::new(con, handle)?)))
}
bitflags! {
#[derive(Default)]
pub struct RegisterRecordFlags: ffi::DNSServiceFlags {
const SHARED = ffi::FLAGS_SHARED;
const UNIQUE = ffi::FLAGS_UNIQUE;
}
}
#[must_use = "futures do nothing unless polled"]
pub struct RegisterRecord(CallbackFuture, Option<::Record>);
impl futures::Future for RegisterRecord {
type Error = io::Error;
type Item = ::Record;
fn poll(&mut self) -> Result<Async<Self::Item>, Self::Error> {
match self.0.poll() {
Ok(Async::Ready(RegisterRecordResult)) => {
Ok(Async::Ready(self.1.take().unwrap()))
},
Ok(Async::NotReady) => Ok(Async::NotReady),
Err(e) => Err(e),
}
}
}
impl GetRemote for RegisterRecord {
fn remote(&self) -> &Remote {
self.0.remote()
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
struct RegisterRecordResult;
extern "C" fn register_record_callback(
_sd_ref: ffi::DNSServiceRef,
_record_ref: ffi::DNSRecordRef,
_flags: ffi::DNSServiceFlags,
error_code: ffi::DNSServiceErrorType,
context: *mut c_void,
) {
CallbackFuture::run_callback(context, error_code, || {
Ok(RegisterRecordResult)
});
}
pub struct RegisterRecordData {
pub flags: RegisterRecordFlags,
pub interface: Interface,
pub rr_class: Class,
pub ttl: u32,
}
impl Default for RegisterRecordData {
fn default() -> Self {
RegisterRecordData {
flags: RegisterRecordFlags::default(),
interface: Interface::default(),
rr_class: Class::IN,
ttl: 0,
}
}
}
impl Connection {
pub fn register_record_extended(
&self,
fullname: &str,
rr_type: Type,
rdata: &[u8],
data: RegisterRecordData,
) -> io::Result<RegisterRecord> {
let fullname = cstr::CStr::from(&fullname)?;
let (serv, record) =
CallbackFuture::new(self.0.clone(), move |sender| {
self.0.service().register_record(
data.flags.bits(),
data.interface.into_raw(),
&fullname,
rr_type,
data.rr_class,
rdata,
data.ttl,
Some(register_record_callback),
sender,
)
})?;
Ok(RegisterRecord(serv, Some(record.into())))
}
pub fn register_record(
&self,
fullname: &str,
rr_type: Type,
rdata: &[u8],
) -> io::Result<RegisterRecord> {
self.register_record_extended(
fullname,
rr_type,
rdata,
RegisterRecordData::default(),
)
}
}
impl RegisterRecord {
fn record(&self) -> &::Record {
self.1.as_ref().expect("RegisterRecord future is done")
}
pub fn rr_type(&self) -> Type {
self.record().rr_type()
}
pub fn update_record(&self, rdata: &[u8], ttl: u32) -> io::Result<()> {
self.record().update_record(rdata, ttl)
}
pub fn keep(self, handle: &Handle) {
let (fut, rec) =
(self.0, self.1.expect("RegisterRecord future is done"));
handle.spawn(fut.then(|_| Ok(())));
rec.keep();
}
}