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 Record,
15 cstr,
16 dns_consts::{
17 Class,
18 Type,
19 },
20 ffi,
21 inner,
22 interface::Interface,
23};
24
25type CallbackFuture = crate::future::ServiceFuture<inner::SharedService, RegisterRecordResult>;
26
27pub struct Connection(inner::SharedService);
29
30#[doc(alias = "DNSServiceCreateConnection")]
35pub fn connect() -> io::Result<Connection> {
36 crate::init();
37
38 Ok(Connection(inner::SharedService::create_connection()?))
39}
40
41bitflags::bitflags! {
42 #[derive(Default)]
44 pub struct RegisterRecordFlags: ffi::DNSServiceFlags {
45 const SHARED = ffi::FLAGS_SHARED;
49
50 const UNIQUE = ffi::FLAGS_UNIQUE;
54 }
55}
56
57#[must_use = "futures do nothing unless polled"]
64pub struct RegisterRecord {
65 future: CallbackFuture,
66 record: Option<Record>,
67}
68
69impl Future for RegisterRecord {
70 type Output = io::Result<Record>;
71
72 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
73 let this = self.get_mut();
74 futures_core::ready!(this.future.poll_unpin(cx))?;
75 Poll::Ready(Ok(this.record.take().unwrap()))
76 }
77}
78
79#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
80struct RegisterRecordResult;
81
82unsafe extern "C" fn register_record_callback(
83 _sd_ref: ffi::DNSServiceRef,
84 _record_ref: ffi::DNSRecordRef,
85 _flags: ffi::DNSServiceFlags,
86 error_code: ffi::DNSServiceErrorType,
87 context: *mut c_void,
88) {
89 unsafe {
90 CallbackFuture::run_callback(context, error_code, || Ok(RegisterRecordResult));
91 }
92}
93
94#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
105pub struct RegisterRecordData {
106 pub flags: RegisterRecordFlags,
108 pub interface: Interface,
110 pub rr_class: Class,
112 pub ttl: u32,
115 #[doc(hidden)]
116 pub _non_exhaustive: crate::non_exhaustive_struct::NonExhaustiveMarker,
117}
118
119impl Default for RegisterRecordData {
120 fn default() -> Self {
121 Self {
122 flags: RegisterRecordFlags::default(),
123 interface: Interface::default(),
124 rr_class: Class::IN,
125 ttl: 0,
126 _non_exhaustive: crate::non_exhaustive_struct::NonExhaustiveMarker,
127 }
128 }
129}
130
131impl Connection {
132 #[doc(alias = "DNSServiceRegisterRecord")]
137 pub fn register_record_extended(
138 &self,
139 fullname: &str,
140 rr_type: Type,
141 rdata: &[u8],
142 data: RegisterRecordData,
143 ) -> io::Result<RegisterRecord> {
144 let fullname = cstr::CStr::from(&fullname)?;
145
146 let (future, record) = CallbackFuture::new_with(self.0.clone(), move |sender| {
147 self.0.clone().register_record(
148 data.flags.bits(),
149 data.interface.into_raw(),
150 &fullname,
151 rr_type,
152 data.rr_class,
153 rdata,
154 data.ttl,
155 Some(register_record_callback),
156 sender,
157 )
158 })?;
159
160 Ok(RegisterRecord {
161 future,
162 record: Some(record.into()),
163 })
164 }
165
166 #[doc(alias = "DNSServiceRegisterRecord")]
173 pub fn register_record(
174 &self,
175 fullname: &str,
176 rr_type: Type,
177 rdata: &[u8],
178 ) -> io::Result<RegisterRecord> {
179 self.register_record_extended(fullname, rr_type, rdata, RegisterRecordData::default())
180 }
181}
182
183impl RegisterRecord {
184 fn inner_record(&self) -> &Record {
185 self.record.as_ref().expect("RegisterRecord future is done")
186 }
187
188 pub fn rr_type(&self) -> Type {
195 self.inner_record().rr_type()
196 }
197
198 #[doc(alias = "DNSServiceUpdateRecord")]
209 pub fn update_record(&self, rdata: &[u8], ttl: u32) -> io::Result<()> {
210 self.inner_record().update_record(rdata, ttl)
211 }
212
213 pub fn keep(self) {
232 let (fut, rec) = (
233 self.future,
234 self.record.expect("RegisterRecord future is done"),
235 );
236 tokio::spawn(fut.map(|_| ()));
238 rec.keep();
239 }
240}