async_dnssd/service/
browse.rs1use std::{
2 io,
3 os::raw::{
4 c_char,
5 c_void,
6 },
7 pin::Pin,
8 task::{
9 Context,
10 Poll,
11 },
12};
13
14use crate::{
15 cstr,
16 ffi,
17 inner,
18 interface::Interface,
19};
20
21type CallbackStream = crate::stream::ServiceStream<inner::OwnedService, BrowseResult>;
22
23bitflags::bitflags! {
24 #[derive(Default)]
26 pub struct BrowsedFlags: ffi::DNSServiceFlags {
27 const MORE_COMING = ffi::FLAGS_MORE_COMING;
32
33 const ADD = ffi::FLAGS_ADD;
38 }
39}
40
41#[must_use = "streams do nothing unless polled"]
45pub struct Browse {
46 stream: crate::fused_err_stream::FusedErrorStream<CallbackStream>,
47}
48
49impl Browse {
50 pin_utils::unsafe_pinned!(stream: crate::fused_err_stream::FusedErrorStream<CallbackStream>);
51}
52
53impl futures_core::Stream for Browse {
54 type Item = io::Result<BrowseResult>;
55
56 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
57 self.stream().poll_next(cx)
58 }
59}
60
61#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
65pub struct BrowseResult {
66 pub flags: BrowsedFlags,
69 pub interface: Interface,
71 pub service_name: String,
73 pub reg_type: String,
75 pub domain: String,
77}
78
79impl BrowseResult {
80 pub fn resolve(&self) -> crate::Resolve {
85 crate::resolve(
86 self.interface,
87 &self.service_name,
88 &self.reg_type,
89 &self.domain,
90 )
91 }
92}
93
94unsafe extern "C" fn browse_callback(
95 _sd_ref: ffi::DNSServiceRef,
96 flags: ffi::DNSServiceFlags,
97 interface_index: u32,
98 error_code: ffi::DNSServiceErrorType,
99 service_name: *const c_char,
100 reg_type: *const c_char,
101 reply_domain: *const c_char,
102 context: *mut c_void,
103) {
104 CallbackStream::run_callback(context, error_code, || {
105 let service_name = cstr::from_cstr(service_name)?;
106 let reg_type = cstr::from_cstr(reg_type)?;
107 let reply_domain = cstr::from_cstr(reply_domain)?;
108
109 Ok(BrowseResult {
110 flags: BrowsedFlags::from_bits_truncate(flags),
111 interface: Interface::from_raw(interface_index),
112 service_name: service_name.to_string(),
113 reg_type: reg_type.to_string(),
114 domain: reply_domain.to_string(),
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")]
196pub fn browse(reg_type: &str) -> Browse {
197 browse_extended(reg_type, BrowseData::default())
198}