async_dnssd/service/
resolve.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 service::{
21 ResolveHost,
22 ResolveHostData,
23 resolve_host_extended,
24 },
25};
26
27type CallbackStream = crate::stream::ServiceStream<inner::OwnedService, ResolveResult>;
28
29bitflags::bitflags! {
30 #[derive(Default)]
32 pub struct ResolvedFlags: ffi::DNSServiceFlags {
33 const MORE_COMING = ffi::FLAGS_MORE_COMING;
38 }
39}
40
41#[must_use = "streams do nothing unless polled"]
43pub struct Resolve {
44 stream: crate::fused_err_stream::FusedErrorStream<CallbackStream>,
45}
46
47impl futures_core::Stream for Resolve {
48 type Item = io::Result<ResolveResult>;
49
50 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
51 let this = self.get_mut();
52 this.stream.poll_next_unpin(cx)
53 }
54}
55
56#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
60pub struct ResolveResult {
61 pub flags: ResolvedFlags,
63 pub interface: Interface,
65 pub fullname: String,
67 pub host_target: String,
69 pub port: u16,
71 pub txt: Vec<u8>,
73}
74
75impl ResolveResult {
76 pub fn resolve_socket_address(&self) -> ResolveHost {
78 let rhdata = ResolveHostData {
79 interface: self.interface,
80 ..Default::default()
81 };
82 resolve_host_extended(&self.host_target, self.port, rhdata)
83 }
84}
85
86unsafe extern "C" fn resolve_callback(
87 _sd_ref: ffi::DNSServiceRef,
88 flags: ffi::DNSServiceFlags,
89 interface_index: u32,
90 error_code: ffi::DNSServiceErrorType,
91 fullname: *const c_char,
92 host_target: *const c_char,
93 port: u16,
94 txt_len: u16,
95 txt_record: *const u8,
96 context: *mut c_void,
97) {
98 unsafe {
99 CallbackStream::run_callback(context, error_code, || {
100 let fullname = cstr::from_cstr(fullname)?;
101 let host_target = cstr::from_cstr(host_target)?;
102 let txt = ::std::slice::from_raw_parts(txt_record, txt_len as usize);
103
104 Ok(ResolveResult {
105 flags: ResolvedFlags::from_bits_truncate(flags),
106 interface: Interface::from_raw(interface_index),
107 fullname: fullname.to_string(),
108 host_target: host_target.to_string(),
109 port: u16::from_be(port),
110 txt: txt.into(),
111 })
112 });
113 }
114}
115
116fn _resolve(interface: Interface, name: &str, reg_type: &str, domain: &str) -> io::Result<Resolve> {
117 crate::init();
118
119 let name = cstr::CStr::from(&name)?;
120 let reg_type = cstr::CStr::from(®_type)?;
121 let domain = cstr::CStr::from(&domain)?;
122
123 let stream = CallbackStream::new(move |sender| {
124 inner::OwnedService::resolve(
125 0, interface.into_raw(),
127 &name,
128 ®_type,
129 &domain,
130 Some(resolve_callback),
131 sender,
132 )
133 })
134 .into();
135
136 Ok(Resolve { stream })
137}
138
139#[doc(alias = "DNSServiceResolve")]
145pub fn resolve(interface: Interface, name: &str, reg_type: &str, domain: &str) -> Resolve {
146 match _resolve(interface, name, reg_type, domain) {
147 Ok(r) => r,
148 Err(e) => Resolve {
149 stream: Err(e).into(),
150 },
151 }
152}