async_zeroconf/
error.rs

1use std::ffi::NulError;
2use std::fmt;
3
4use crate::Service;
5use bonjour_sys::DNSServiceErrorType;
6use std::error::Error;
7use std::str::Utf8Error;
8use std::sync::PoisonError;
9
10/// Custom error holding any potential errors from publishing or browsing for
11/// services.
12#[derive(Debug)]
13pub enum ZeroconfError {
14    /// An error from the Bonjour API ([BonjourError])
15    Bonjour(BonjourError),
16    /// An IO error on the internal socket used to poll for events
17    Io(std::io::Error),
18    /// A timeout occurred before the operation was complete
19    ///
20    /// Contains the service that could not be resolved. This is only valid
21    /// for resolve operations as browsing does not have a specific endpoint
22    /// and so timing out is not an error.
23    Timeout(Service),
24    /// The service type specified is invalid
25    InvalidServiceType(String),
26    /// The TXT record specified is invalid
27    InvalidTxtRecord(String),
28    /// A service was passed to resolve that was not from a
29    /// [ServiceBrowser][crate::ServiceBrowser].
30    ///
31    /// This is an error as the resolve operation requires the information
32    /// about domain, interface and so on to be in the format provided from
33    /// the browse operation.
34    NotFromBrowser(Service),
35    /// Null byte in a string conversion
36    NullString(NulError),
37    /// Poisoned Mutex
38    Poison,
39    /// Failed to convert to a UTF-8 string
40    Utf8(Utf8Error),
41    /// Interface not found
42    InterfaceNotFound(String),
43    /// Dropped a task
44    Dropped,
45}
46
47impl From<PoisonError<std::sync::MutexGuard<'_, ()>>> for ZeroconfError {
48    fn from(_: PoisonError<std::sync::MutexGuard<'_, ()>>) -> Self {
49        ZeroconfError::Poison
50    }
51}
52
53impl From<NulError> for ZeroconfError {
54    fn from(s: NulError) -> Self {
55        ZeroconfError::NullString(s)
56    }
57}
58
59impl From<Utf8Error> for ZeroconfError {
60    fn from(s: Utf8Error) -> Self {
61        ZeroconfError::Utf8(s)
62    }
63}
64
65impl From<std::io::Error> for ZeroconfError {
66    fn from(s: std::io::Error) -> Self {
67        ZeroconfError::Io(s)
68    }
69}
70
71impl From<i32> for ZeroconfError {
72    fn from(s: i32) -> Self {
73        ZeroconfError::Bonjour(s.into())
74    }
75}
76
77impl From<BonjourError> for ZeroconfError {
78    fn from(s: BonjourError) -> Self {
79        ZeroconfError::Bonjour(s)
80    }
81}
82
83impl fmt::Display for ZeroconfError {
84    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85        let s = match self {
86            ZeroconfError::Bonjour(e) => format!("error from bonjour - {}", e),
87            ZeroconfError::Io(e) => e.to_string(),
88            ZeroconfError::Timeout(s) => format!("timeout on {}", s.service_type()),
89            ZeroconfError::InvalidServiceType(s) => format!("invalid service type '{}'", s),
90            ZeroconfError::InvalidTxtRecord(s) => format!("invalid txt record '{}'", s),
91            ZeroconfError::NotFromBrowser(s) => {
92                format!("'{}' service not from browser", s.service_type())
93            }
94            ZeroconfError::NullString(s) => s.to_string(),
95            ZeroconfError::Poison => "mutex was poisoned".to_string(),
96            ZeroconfError::Utf8(e) => e.to_string(),
97            ZeroconfError::InterfaceNotFound(s) => format!("interface not found '{}'", s),
98            ZeroconfError::Dropped => "task dropped before expected".to_string(),
99        };
100        write!(f, "{}", s)
101    }
102}
103
104impl Error for ZeroconfError {
105    fn source(&self) -> Option<&(dyn Error + 'static)> {
106        match self {
107            ZeroconfError::Bonjour(e) => Some(e),
108            ZeroconfError::Io(e) => Some(e),
109            ZeroconfError::NullString(e) => Some(e),
110            ZeroconfError::Utf8(e) => Some(e),
111            _ => None,
112        }
113    }
114}
115
116/// An error from the Bonjour API
117///
118/// Further information about the requirements for service parameters can be
119/// found in the [Bonjour API][b] documentation.
120///
121/// [b]: https://developer.apple.com/documentation/dnssd/dns_service_discovery_c
122#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
123pub enum BonjourError {
124    /// Unknown error
125    Unknown,
126    /// No such name
127    NoSuchName,
128    /// Out of memory
129    NoMemory,
130    /// Bad parameter passed to function
131    BadParam,
132    /// Bad reference
133    BadReference,
134    /// Bad state
135    BadState,
136    /// Unexpected flags to function
137    BadFlags,
138    /// Unsupported
139    Unsupported,
140    /// Not initialized
141    NotInitialized,
142    /// Already registered
143    AlreadyRegistered,
144    /// Name conflicts with existing service
145    NameConflict,
146    /// Invalid index or character
147    Invalid,
148    /// Firewall
149    Firewall,
150    /// Client library incompatible with daemon
151    Incompatible,
152    /// Interface index doesn't exist
153    BadInterfaceIndex,
154    /// Refused
155    Refused,
156    /// No such record
157    NoSuchRecord,
158    /// No auth
159    NoAuth,
160    /// Key does not exist in TXT record
161    NoSuchKey,
162    /// NAT traversal
163    NATTraversal,
164    /// More than one NAT gateway between source and destination
165    DoubleNAT,
166    /// Bad time
167    BadTime,
168    /// Undefined error
169    Undefined,
170}
171
172impl fmt::Display for BonjourError {
173    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174        let s = match self {
175            BonjourError::Unknown => "unknown error",
176            BonjourError::NoSuchName => "no such name",
177            BonjourError::NoMemory => "no memory",
178            BonjourError::BadParam => "bad parameter",
179            BonjourError::BadReference => "bad reference",
180            BonjourError::BadState => "bad state",
181            BonjourError::BadFlags => "bad flags",
182            BonjourError::Unsupported => "unsupported",
183            BonjourError::NotInitialized => "not initialized",
184            BonjourError::AlreadyRegistered => "already registered",
185            BonjourError::NameConflict => "name conflict",
186            BonjourError::Invalid => "invalid",
187            BonjourError::Firewall => "firewall",
188            BonjourError::Incompatible => "incompatible",
189            BonjourError::BadInterfaceIndex => "bad interface index",
190            BonjourError::Refused => "refused",
191            BonjourError::NoSuchRecord => "no such record",
192            BonjourError::NoAuth => "no auth",
193            BonjourError::NoSuchKey => "no such key",
194            BonjourError::NATTraversal => "NAT traversal",
195            BonjourError::DoubleNAT => "double NAT",
196            BonjourError::BadTime => "bad time",
197            BonjourError::Undefined => "undefined error",
198        };
199        write!(f, "{}", s)
200    }
201}
202
203impl std::error::Error for BonjourError {}
204
205impl From<DNSServiceErrorType> for BonjourError {
206    fn from(err: DNSServiceErrorType) -> Self {
207        match err {
208            -65537 => BonjourError::Unknown,
209            -65538 => BonjourError::NoSuchName,
210            -65539 => BonjourError::NoMemory,
211            -65540 => BonjourError::BadParam,
212            -65541 => BonjourError::BadReference,
213            -65542 => BonjourError::BadState,
214            -65543 => BonjourError::BadFlags,
215            -65544 => BonjourError::Unsupported,
216            -65545 => BonjourError::NotInitialized,
217            -65547 => BonjourError::AlreadyRegistered,
218            -65548 => BonjourError::NameConflict,
219            -65549 => BonjourError::Invalid,
220            -65550 => BonjourError::Firewall,
221            -65551 => BonjourError::Incompatible,
222            -65552 => BonjourError::BadInterfaceIndex,
223            -65553 => BonjourError::Refused,
224            -65554 => BonjourError::NoSuchRecord,
225            -65555 => BonjourError::NoAuth,
226            -65556 => BonjourError::NoSuchKey,
227            -65557 => BonjourError::NATTraversal,
228            -65558 => BonjourError::DoubleNAT,
229            -65559 => BonjourError::BadTime,
230            _ => BonjourError::Undefined,
231        }
232    }
233}