use futures::{
self,
Async,
};
use std::{
io,
os::raw::{
c_char,
c_void,
},
};
use tokio_core::reactor::{
Handle,
Remote,
};
use cstr;
use ffi;
use interface::Interface;
use raw;
use remote::GetRemote;
type CallbackStream = ::stream::ServiceStream<BrowseResult>;
bitflags! {
#[derive(Default)]
pub struct BrowsedFlags: ffi::DNSServiceFlags {
const MORE_COMING = ffi::FLAGS_MORE_COMING;
const ADD = ffi::FLAGS_ADD;
}
}
#[must_use = "streams do nothing unless polled"]
pub struct Browse(CallbackStream);
impl futures::Stream for Browse {
type Error = io::Error;
type Item = BrowseResult;
fn poll(&mut self) -> Result<Async<Option<Self::Item>>, Self::Error> {
self.0.poll()
}
}
impl GetRemote for Browse {
fn remote(&self) -> &Remote {
self.0.remote()
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct BrowseResult {
pub flags: BrowsedFlags,
pub interface: Interface,
pub service_name: String,
pub reg_type: String,
pub domain: String,
}
impl BrowseResult {
pub fn resolve(&self, handle: &Handle) -> io::Result<::Resolve> {
::resolve(
self.interface,
&self.service_name,
&self.reg_type,
&self.domain,
handle,
)
}
}
extern "C" fn browse_callback(
_sd_ref: ffi::DNSServiceRef,
flags: ffi::DNSServiceFlags,
interface_index: u32,
error_code: ffi::DNSServiceErrorType,
service_name: *const c_char,
reg_type: *const c_char,
reply_domain: *const c_char,
context: *mut c_void,
) {
CallbackStream::run_callback(context, error_code, || {
let service_name = unsafe { cstr::from_cstr(service_name) }?;
let reg_type = unsafe { cstr::from_cstr(reg_type) }?;
let reply_domain = unsafe { cstr::from_cstr(reply_domain) }?;
Ok(BrowseResult {
flags: BrowsedFlags::from_bits_truncate(flags),
interface: Interface::from_raw(interface_index),
service_name: service_name.to_string(),
reg_type: reg_type.to_string(),
domain: reply_domain.to_string(),
})
});
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct BrowseData<'a> {
pub interface: Interface,
pub domain: Option<&'a str>,
}
impl<'a> Default for BrowseData<'a> {
fn default() -> Self {
BrowseData {
interface: Interface::default(),
domain: None,
}
}
}
pub fn browse_extended(
reg_type: &str,
data: BrowseData,
handle: &Handle,
) -> io::Result<Browse> {
::init();
let reg_type = cstr::CStr::from(®_type)?;
let domain = cstr::NullableCStr::from(&data.domain)?;
Ok(Browse(CallbackStream::new(handle, move |sender| {
raw::DNSService::browse(
0, data.interface.into_raw(),
®_type,
&domain,
Some(browse_callback),
sender,
)
})?))
}
pub fn browse(reg_type: &str, handle: &Handle) -> io::Result<Browse> {
browse_extended(reg_type, BrowseData::default(), handle)
}