async_dnssd/service/
enumerate_domains.rs

1use futures_util::StreamExt;
2use std::{
3	io,
4	os::raw::{
5		c_char,
6		c_void,
7	},
8	pin::Pin,
9	task::{
10		Context,
11		Poll,
12	},
13};
14
15use crate::{
16	cstr,
17	ffi,
18	inner,
19	interface::Interface,
20};
21
22type CallbackStream = crate::stream::ServiceStream<inner::OwnedService, EnumerateResult>;
23
24/// Whether to enumerate domains which are browsed or domains for which
25/// registrations can be made.
26#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
27pub enum Enumerate {
28	/// enumerate domains which can be browsed
29	BrowseDomains,
30	/// enumerate domains to register services/records on
31	RegistrationDomains,
32}
33
34impl From<Enumerate> for ffi::DNSServiceFlags {
35	fn from(e: Enumerate) -> Self {
36		match e {
37			Enumerate::BrowseDomains => ffi::FLAGS_BROWSE_DOMAINS,
38			Enumerate::RegistrationDomains => ffi::FLAGS_REGISTRATION_DOMAINS,
39		}
40	}
41}
42
43bitflags::bitflags! {
44	/// Flags for [`EnumerateDomains`]
45	#[derive(Default)]
46	pub struct EnumeratedFlags: ffi::DNSServiceFlags {
47		/// Indicates at least one more result is pending in the queue.  If
48		/// not set there still might be more results coming in the future.
49		///
50		/// See [`kDNSServiceFlagsMoreComing`](https://developer.apple.com/documentation/dnssd/1823436-anonymous/kdnsserviceflagsmorecoming).
51		const MORE_COMING = ffi::FLAGS_MORE_COMING;
52
53		/// Indicates the result is new.  If not set indicates the result
54		/// was removed.
55		///
56		/// See [`kDNSServiceFlagsAdd`](https://developer.apple.com/documentation/dnssd/1823436-anonymous/kdnsserviceflagsadd).
57		const ADD = ffi::FLAGS_ADD;
58
59		/// Indicates this is the default domain to search (always combined with `Add`).
60		///
61		/// See [`kDNSServiceFlagsDefault`](https://developer.apple.com/documentation/dnssd/1823436-anonymous/kdnsserviceflagsdefault).
62		const DEFAULT = ffi::FLAGS_DEFAULT;
63	}
64}
65
66/// Pending domain enumeration
67#[must_use = "streams do nothing unless polled"]
68pub struct EnumerateDomains {
69	stream: crate::fused_err_stream::FusedErrorStream<CallbackStream>,
70}
71
72impl futures_core::Stream for EnumerateDomains {
73	type Item = io::Result<EnumerateResult>;
74
75	fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
76		let this = self.get_mut();
77		this.stream.poll_next_unpin(cx)
78	}
79}
80
81/// Domain enumeration result
82///
83/// See [DNSServiceDomainEnumReply](https://developer.apple.com/documentation/dnssd/dnsservicedomainenumreply).
84#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
85pub struct EnumerateResult {
86	/// flags
87	pub flags: EnumeratedFlags,
88	/// interface domain was found on
89	pub interface: Interface,
90	/// domain name
91	pub domain: String,
92}
93
94unsafe extern "C" fn enumerate_callback(
95	_sd_ref: ffi::DNSServiceRef,
96	flags: ffi::DNSServiceFlags,
97	interface_index: u32,
98	error_code: ffi::DNSServiceErrorType,
99	reply_domain: *const c_char,
100	context: *mut c_void,
101) {
102	unsafe {
103		CallbackStream::run_callback(context, error_code, || {
104			let reply_domain = cstr::from_cstr(reply_domain)?;
105
106			Ok(EnumerateResult {
107				flags: EnumeratedFlags::from_bits_truncate(flags),
108				interface: Interface::from_raw(interface_index),
109				domain: reply_domain.to_string(),
110			})
111		});
112	}
113}
114
115/// Enumerate domains that are recommended for registration or browsing
116///
117/// See [`DNSServiceEnumerateDomains`](https://developer.apple.com/documentation/dnssd/1804754-dnsserviceenumeratedomains).
118#[doc(alias = "DNSServiceEnumerateDomains")]
119pub fn enumerate_domains(enumerate: Enumerate, interface: Interface) -> EnumerateDomains {
120	crate::init();
121
122	let stream = CallbackStream::new(move |sender| {
123		inner::OwnedService::enumerate_domains(
124			enumerate.into(),
125			interface.into_raw(),
126			Some(enumerate_callback),
127			sender,
128		)
129	})
130	.into();
131
132	EnumerateDomains { stream }
133}