1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
use futures::sync::mpsc;
use futures::{self,Async};
use std::os::raw::{c_void,c_char};
use std::io;
use tokio_core::reactor::{Handle,Remote};

use cstr;
use error::Error;
use evented::EventedDNSService;
use ffi;
use interface::Interface;
use raw;
use remote::GetRemote;
use stream::ServiceStream;

/// Pending resolve request
pub struct Resolve(ServiceStream<ResolveResult>);

impl futures::Stream for Resolve {
	type Item = ResolveResult;
	type Error = io::Error;

	fn poll(&mut self) -> Result<Async<Option<Self::Item>>, Self::Error> {
		self.0.poll()
	}
}

impl GetRemote for Resolve {
	fn remote(&self) -> &Remote {
		self.0.remote()
	}
}

/// Resolve result
///
/// See [`DNSServiceResolveReply`](https://developer.apple.com/documentation/dnssd/dnsserviceresolvereply).
#[derive(Clone,PartialEq,Eq,PartialOrd,Ord,Hash,Debug)]
pub struct ResolveResult{
	///
	pub interface: Interface,
	///
	pub fullname: String,
	///
	pub host_target: String,
	///
	pub port: u16,
	///
	pub txt: Vec<u8>,
}

extern "C" fn resolve_callback(
	_sd_ref: ffi::DNSServiceRef,
	_flags: ffi::DNSServiceFlags,
	interface_index: u32,
	error_code: ffi::DNSServiceErrorType,
	fullname: *const c_char,
	host_target: *const c_char,
	port: u16,
	txt_len: u16,
	txt_record: *const u8,
	context: *mut c_void
) {
	let sender = context as *mut mpsc::UnboundedSender<io::Result<ResolveResult>>;
	let sender : &mpsc::UnboundedSender<io::Result<ResolveResult>> = unsafe { &*sender };

	let data = Error::from(error_code).map_err(io::Error::from).and_then(|_| {
		let fullname = unsafe { cstr::from_cstr(fullname) }?;
		let host_target = unsafe { cstr::from_cstr(host_target) }?;
		let txt = unsafe { ::std::slice::from_raw_parts(txt_record, txt_len as usize) };

		Ok(ResolveResult{
			interface: Interface::from_raw(interface_index),
			fullname: fullname.to_string(),
			host_target: host_target.to_string(),
			port: u16::from_be(port),
			txt: txt.into(),
		})
	});

	sender.send(data).unwrap();
}

/// Find hostname and port (and more) for a service
///
/// See [`DNSServiceResolve`](https://developer.apple.com/documentation/dnssd/1804744-dnsserviceresolve).
pub fn resolve(
	interface: Interface,
	name: &str,
	reg_type: &str,
	domain: &str,
	handle: &Handle
) -> io::Result<Resolve> {
	let name = cstr::CStr::from(&name)?;
	let reg_type = cstr::CStr::from(&reg_type)?;
	let domain = cstr::CStr::from(&domain)?;

	Ok(Resolve(ServiceStream::new(move |sender|
		EventedDNSService::new(
			raw::DNSService::resolve(
				0, /* no flags */
				interface.into_raw(),
				&name,
				&reg_type,
				&domain,
				Some(resolve_callback),
				sender as *mut c_void,
			)?,
			handle
		)
	)?))
}