async_dnssd/service/
browse.rs1use 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, BrowseResult>;
23
24bitflags::bitflags! {
25 #[derive(Default)]
27 pub struct BrowsedFlags: ffi::DNSServiceFlags {
28 const MORE_COMING = ffi::FLAGS_MORE_COMING;
33
34 const ADD = ffi::FLAGS_ADD;
39 }
40}
41
42#[must_use = "streams do nothing unless polled"]
46pub struct Browse {
47 stream: crate::fused_err_stream::FusedErrorStream<CallbackStream>,
48}
49
50impl futures_core::Stream for Browse {
51 type Item = io::Result<BrowseResult>;
52
53 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
54 let this = self.get_mut();
55 this.stream.poll_next_unpin(cx)
56 }
57}
58
59#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
63pub struct BrowseResult {
64 pub flags: BrowsedFlags,
67 pub interface: Interface,
69 pub service_name: String,
71 pub reg_type: String,
73 pub domain: String,
75}
76
77impl BrowseResult {
78 pub fn resolve(&self) -> crate::Resolve {
83 crate::resolve(
84 self.interface,
85 &self.service_name,
86 &self.reg_type,
87 &self.domain,
88 )
89 }
90}
91
92unsafe extern "C" fn browse_callback(
93 _sd_ref: ffi::DNSServiceRef,
94 flags: ffi::DNSServiceFlags,
95 interface_index: u32,
96 error_code: ffi::DNSServiceErrorType,
97 service_name: *const c_char,
98 reg_type: *const c_char,
99 reply_domain: *const c_char,
100 context: *mut c_void,
101) {
102 unsafe {
103 CallbackStream::run_callback(context, error_code, || {
104 let service_name = cstr::from_cstr(service_name)?;
105 let reg_type = cstr::from_cstr(reg_type)?;
106 let reply_domain = cstr::from_cstr(reply_domain)?;
107
108 Ok(BrowseResult {
109 flags: BrowsedFlags::from_bits_truncate(flags),
110 interface: Interface::from_raw(interface_index),
111 service_name: service_name.to_string(),
112 reg_type: reg_type.to_string(),
113 domain: reply_domain.to_string(),
114 })
115 });
116 }
117}
118
119#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
130pub struct BrowseData<'a> {
131 pub interface: Interface,
133 pub domain: Option<&'a str>,
135 #[doc(hidden)]
136 pub _non_exhaustive: crate::non_exhaustive_struct::NonExhaustiveMarker,
137}
138
139impl<'a> Default for BrowseData<'a> {
140 fn default() -> Self {
141 Self {
142 interface: Interface::default(),
143 domain: None,
144 _non_exhaustive: crate::non_exhaustive_struct::NonExhaustiveMarker,
145 }
146 }
147}
148
149fn _browse_extended(reg_type: &str, data: BrowseData<'_>) -> io::Result<Browse> {
150 crate::init();
151
152 let reg_type = cstr::CStr::from(®_type)?;
153 let domain = cstr::NullableCStr::from(&data.domain)?;
154
155 let stream = CallbackStream::new(move |sender| {
156 inner::OwnedService::browse(
157 0, data.interface.into_raw(),
159 ®_type,
160 &domain,
161 Some(browse_callback),
162 sender,
163 )
164 })
165 .into();
166
167 Ok(Browse { stream })
168}
169
170#[doc(alias = "DNSServiceBrowse")]
176pub fn browse_extended(reg_type: &str, data: BrowseData<'_>) -> Browse {
177 match _browse_extended(reg_type, data) {
178 Ok(r) => r,
179 Err(e) => Browse {
180 stream: Err(e).into(),
181 },
182 }
183}
184
185#[doc(alias = "DNSServiceBrowse")]
193pub fn browse(reg_type: &str) -> Browse {
194 browse_extended(reg_type, BrowseData::default())
195}