async_dnssd/service/
resolve.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 service::{
20 resolve_host_extended,
21 ResolveHost,
22 ResolveHostData,
23 },
24};
25
26type CallbackStream = crate::stream::ServiceStream<inner::OwnedService, ResolveResult>;
27
28bitflags::bitflags! {
29 #[derive(Default)]
31 pub struct ResolvedFlags: ffi::DNSServiceFlags {
32 const MORE_COMING = ffi::FLAGS_MORE_COMING;
37 }
38}
39
40#[must_use = "streams do nothing unless polled"]
42pub struct Resolve {
43 stream: crate::fused_err_stream::FusedErrorStream<CallbackStream>,
44}
45
46impl Resolve {
47 pin_utils::unsafe_pinned!(stream: crate::fused_err_stream::FusedErrorStream<CallbackStream>);
48}
49
50impl futures_core::Stream for Resolve {
51 type Item = io::Result<ResolveResult>;
52
53 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
54 self.stream().poll_next(cx)
55 }
56}
57
58#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
62pub struct ResolveResult {
63 pub flags: ResolvedFlags,
65 pub interface: Interface,
67 pub fullname: String,
69 pub host_target: String,
71 pub port: u16,
73 pub txt: Vec<u8>,
75}
76
77impl ResolveResult {
78 pub fn resolve_socket_address(&self) -> ResolveHost {
80 let rhdata = ResolveHostData {
81 interface: self.interface,
82 ..Default::default()
83 };
84 resolve_host_extended(&self.host_target, self.port, rhdata)
85 }
86}
87
88unsafe extern "C" fn resolve_callback(
89 _sd_ref: ffi::DNSServiceRef,
90 flags: ffi::DNSServiceFlags,
91 interface_index: u32,
92 error_code: ffi::DNSServiceErrorType,
93 fullname: *const c_char,
94 host_target: *const c_char,
95 port: u16,
96 txt_len: u16,
97 txt_record: *const u8,
98 context: *mut c_void,
99) {
100 CallbackStream::run_callback(context, error_code, || {
101 let fullname = cstr::from_cstr(fullname)?;
102 let host_target = cstr::from_cstr(host_target)?;
103 let txt = ::std::slice::from_raw_parts(txt_record, txt_len as usize);
104
105 Ok(ResolveResult {
106 flags: ResolvedFlags::from_bits_truncate(flags),
107 interface: Interface::from_raw(interface_index),
108 fullname: fullname.to_string(),
109 host_target: host_target.to_string(),
110 port: u16::from_be(port),
111 txt: txt.into(),
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")]
147pub fn resolve(interface: Interface, name: &str, reg_type: &str, domain: &str) -> Resolve {
148 match _resolve(interface, name, reg_type, domain) {
149 Ok(r) => r,
150 Err(e) => Resolve {
151 stream: Err(e).into(),
152 },
153 }
154}