async_dnssd/service/
connection.rs1use futures_util::FutureExt;
2use std::{
3 future::Future,
4 io,
5 os::raw::c_void,
6 pin::Pin,
7 task::{
8 Context,
9 Poll,
10 },
11};
12
13use crate::{
14 cstr,
15 dns_consts::{
16 Class,
17 Type,
18 },
19 ffi,
20 inner,
21 interface::Interface,
22};
23
24type CallbackFuture = crate::future::ServiceFuture<inner::SharedService, RegisterRecordResult>;
25
26pub struct Connection(inner::SharedService);
28
29#[doc(alias = "DNSServiceCreateConnection")]
34pub fn connect() -> io::Result<Connection> {
35 crate::init();
36
37 Ok(Connection(inner::SharedService::create_connection()?))
38}
39
40bitflags::bitflags! {
41 #[derive(Default)]
43 pub struct RegisterRecordFlags: ffi::DNSServiceFlags {
44 const SHARED = ffi::FLAGS_SHARED;
48
49 const UNIQUE = ffi::FLAGS_UNIQUE;
53 }
54}
55
56#[must_use = "futures do nothing unless polled"]
63pub struct RegisterRecord {
64 future: CallbackFuture,
65 record: Option<crate::Record>,
66}
67
68impl RegisterRecord {
69 pin_utils::unsafe_pinned!(future: CallbackFuture);
70
71 pin_utils::unsafe_unpinned!(record: Option<crate::Record>);
72}
73
74impl Future for RegisterRecord {
75 type Output = io::Result<crate::Record>;
76
77 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
78 futures_core::ready!(self.as_mut().future().poll(cx))?;
79 Poll::Ready(Ok(self.record().take().unwrap()))
80 }
81}
82
83#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
84struct RegisterRecordResult;
85
86unsafe extern "C" fn register_record_callback(
87 _sd_ref: ffi::DNSServiceRef,
88 _record_ref: ffi::DNSRecordRef,
89 _flags: ffi::DNSServiceFlags,
90 error_code: ffi::DNSServiceErrorType,
91 context: *mut c_void,
92) {
93 CallbackFuture::run_callback(context, error_code, || Ok(RegisterRecordResult));
94}
95
96#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
107pub struct RegisterRecordData {
108 pub flags: RegisterRecordFlags,
110 pub interface: Interface,
112 pub rr_class: Class,
114 pub ttl: u32,
117 #[doc(hidden)]
118 pub _non_exhaustive: crate::non_exhaustive_struct::NonExhaustiveMarker,
119}
120
121impl Default for RegisterRecordData {
122 fn default() -> Self {
123 Self {
124 flags: RegisterRecordFlags::default(),
125 interface: Interface::default(),
126 rr_class: Class::IN,
127 ttl: 0,
128 _non_exhaustive: crate::non_exhaustive_struct::NonExhaustiveMarker,
129 }
130 }
131}
132
133impl Connection {
134 #[doc(alias = "DNSServiceRegisterRecord")]
139 pub fn register_record_extended(
140 &self,
141 fullname: &str,
142 rr_type: Type,
143 rdata: &[u8],
144 data: RegisterRecordData,
145 ) -> io::Result<RegisterRecord> {
146 let fullname = cstr::CStr::from(&fullname)?;
147
148 let (future, record) = CallbackFuture::new_with(self.0.clone(), move |sender| {
149 self.0.clone().register_record(
150 data.flags.bits(),
151 data.interface.into_raw(),
152 &fullname,
153 rr_type,
154 data.rr_class,
155 rdata,
156 data.ttl,
157 Some(register_record_callback),
158 sender,
159 )
160 })?;
161
162 Ok(RegisterRecord {
163 future,
164 record: Some(record.into()),
165 })
166 }
167
168 #[doc(alias = "DNSServiceRegisterRecord")]
178 pub fn register_record(
179 &self,
180 fullname: &str,
181 rr_type: Type,
182 rdata: &[u8],
183 ) -> io::Result<RegisterRecord> {
184 self.register_record_extended(fullname, rr_type, rdata, RegisterRecordData::default())
185 }
186}
187
188impl RegisterRecord {
189 fn inner_record(&self) -> &crate::Record {
190 self.record.as_ref().expect("RegisterRecord future is done")
191 }
192
193 pub fn rr_type(&self) -> Type {
200 self.inner_record().rr_type()
201 }
202
203 #[doc(alias = "DNSServiceUpdateRecord")]
214 pub fn update_record(&self, rdata: &[u8], ttl: u32) -> io::Result<()> {
215 self.inner_record().update_record(rdata, ttl)
216 }
217
218 pub fn keep(self) {
237 let (fut, rec) = (
238 self.future,
239 self.record.expect("RegisterRecord future is done"),
240 );
241 tokio::spawn(fut.map(|_| ()));
243 rec.keep();
244 }
245}