veilid_igd/
errors.rs

1use std::error;
2use std::fmt;
3use std::io;
4use std::str;
5#[cfg(any(feature = "aio_tokio", feature = "aio_async_std"))]
6use std::string::FromUtf8Error;
7
8#[cfg(feature = "aio_tokio")]
9use tokio::time::error::Elapsed;
10
11#[cfg(feature = "aio_async_std")]
12use async_std::future::TimeoutError;
13
14/// Errors that can occur when sending the request to the gateway.
15#[derive(Debug)]
16pub enum RequestError {
17    /// attohttp error
18    AttoHttpError(attohttpc::Error),
19    /// IO Error
20    IoError(io::Error),
21    /// The response from the gateway could not be parsed.
22    InvalidResponse(String),
23    /// The gateway returned an unhandled error code and description.
24    ErrorCode(u16, String),
25    /// Action is not supported by the gateway
26    UnsupportedAction(String),
27    /// When using the aio feature.
28    #[cfg(feature = "aio_tokio")]
29    HyperError(hyper::Error),
30
31    /// When using aio async std feature
32    #[cfg(feature = "aio_async_std")]
33    SurfError(surf::Error),
34
35    #[cfg(any(feature = "aio_tokio", feature = "aio_async_std"))]
36    /// http crate error type
37    HttpError(http::Error),
38
39    #[cfg(any(feature = "aio_tokio", feature = "aio_async_std"))]
40    /// Error parsing HTTP body
41    Utf8Error(FromUtf8Error),
42}
43
44impl From<attohttpc::Error> for RequestError {
45    fn from(err: attohttpc::Error) -> RequestError {
46        RequestError::AttoHttpError(err)
47    }
48}
49
50impl From<io::Error> for RequestError {
51    fn from(err: io::Error) -> RequestError {
52        RequestError::IoError(err)
53    }
54}
55
56#[cfg(any(feature = "aio_tokio", feature = "aio_async_std"))]
57impl From<http::Error> for RequestError {
58    fn from(err: http::Error) -> RequestError {
59        RequestError::HttpError(err)
60    }
61}
62
63#[cfg(feature = "aio_async_std")]
64impl From<surf::Error> for RequestError {
65    fn from(err: surf::Error) -> RequestError {
66        RequestError::SurfError(err)
67    }
68}
69
70#[cfg(feature = "aio_tokio")]
71impl From<hyper::Error> for RequestError {
72    fn from(err: hyper::Error) -> RequestError {
73        RequestError::HyperError(err)
74    }
75}
76
77#[cfg(any(feature = "aio_tokio", feature = "aio_async_std"))]
78impl From<FromUtf8Error> for RequestError {
79    fn from(err: FromUtf8Error) -> RequestError {
80        RequestError::Utf8Error(err)
81    }
82}
83
84#[cfg(feature = "aio_async_std")]
85impl From<TimeoutError> for RequestError {
86    fn from(_err: TimeoutError) -> RequestError {
87        RequestError::IoError(io::Error::new(io::ErrorKind::TimedOut, "timer failed"))
88    }
89}
90
91#[cfg(feature = "aio_tokio")]
92impl From<Elapsed> for RequestError {
93    fn from(_err: Elapsed) -> RequestError {
94        RequestError::IoError(io::Error::new(io::ErrorKind::TimedOut, "timer failed"))
95    }
96}
97
98impl fmt::Display for RequestError {
99    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
100        match *self {
101            RequestError::AttoHttpError(ref e) => write!(f, "HTTP error {e}"),
102            RequestError::InvalidResponse(ref e) => write!(f, "Invalid response from gateway: {e}"),
103            RequestError::IoError(ref e) => write!(f, "IO error. {e}"),
104            RequestError::ErrorCode(n, ref e) => write!(f, "Gateway response error {n}: {e}"),
105            RequestError::UnsupportedAction(ref e) => write!(f, "Gateway does not support action: {e}"),
106            #[cfg(feature = "aio_async_std")]
107            RequestError::SurfError(ref e) => write!(f, "Surf Error: {e}"),
108            #[cfg(feature = "aio_tokio")]
109            RequestError::HyperError(ref e) => write!(f, "Hyper Error: {e}"),
110            #[cfg(any(feature = "aio_tokio", feature = "aio_async_std"))]
111            RequestError::HttpError(ref e) => write!(f, "Http  Error: {e}"),
112            #[cfg(any(feature = "aio_tokio", feature = "aio_async_std"))]
113            RequestError::Utf8Error(ref e) => write!(f, "Utf8Error Error: {e}"),
114        }
115    }
116}
117
118impl std::error::Error for RequestError {
119    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
120        match *self {
121            RequestError::AttoHttpError(ref e) => Some(e),
122            RequestError::InvalidResponse(..) => None,
123            RequestError::IoError(ref e) => Some(e),
124            RequestError::ErrorCode(..) => None,
125            RequestError::UnsupportedAction(..) => None,
126            #[cfg(feature = "aio_async_std")]
127            RequestError::SurfError(ref e) => Some(e.as_ref()),
128            #[cfg(feature = "aio_tokio")]
129            RequestError::HyperError(ref e) => Some(e),
130            #[cfg(any(feature = "aio_tokio", feature = "aio_async_std"))]
131            RequestError::HttpError(ref e) => Some(e),
132            #[cfg(any(feature = "aio_tokio", feature = "aio_async_std"))]
133            RequestError::Utf8Error(ref e) => Some(e),
134        }
135    }
136}
137
138/// Errors returned by `Gateway::get_external_ip`
139#[derive(Debug)]
140pub enum GetExternalIpError {
141    /// The client is not authorized to perform the operation.
142    ActionNotAuthorized,
143    /// Some other error occured performing the request.
144    RequestError(RequestError),
145}
146
147/// Errors returned by `Gateway::remove_port`
148#[derive(Debug)]
149pub enum RemovePortError {
150    /// The client is not authorized to perform the operation.
151    ActionNotAuthorized,
152    /// No such port mapping.
153    NoSuchPortMapping,
154    /// Some other error occured performing the request.
155    RequestError(RequestError),
156}
157
158/// Errors returned by `Gateway::add_any_port` and `Gateway::get_any_address`
159#[derive(Debug)]
160pub enum AddAnyPortError {
161    /// The client is not authorized to perform the operation.
162    ActionNotAuthorized,
163    /// Can not add a mapping for local port 0.
164    InternalPortZeroInvalid,
165    /// The gateway does not have any free ports.
166    NoPortsAvailable,
167    /// The gateway can only map internal ports to same-numbered external ports
168    /// and this external port is in use.
169    ExternalPortInUse,
170    /// The gateway only supports permanent leases (ie. a `lease_duration` of 0).
171    OnlyPermanentLeasesSupported,
172    /// The description was too long for the gateway to handle.
173    DescriptionTooLong,
174    /// Some other error occured performing the request.
175    RequestError(RequestError),
176}
177
178impl From<RequestError> for AddAnyPortError {
179    fn from(err: RequestError) -> AddAnyPortError {
180        AddAnyPortError::RequestError(err)
181    }
182}
183
184impl From<GetExternalIpError> for AddAnyPortError {
185    fn from(err: GetExternalIpError) -> AddAnyPortError {
186        match err {
187            GetExternalIpError::ActionNotAuthorized => AddAnyPortError::ActionNotAuthorized,
188            GetExternalIpError::RequestError(e) => AddAnyPortError::RequestError(e),
189        }
190    }
191}
192
193/// Errors returned by `Gateway::add_port`
194#[derive(Debug)]
195pub enum AddPortError {
196    /// The client is not authorized to perform the operation.
197    ActionNotAuthorized,
198    /// Can not add a mapping for local port 0.
199    InternalPortZeroInvalid,
200    /// External port number 0 (any port) is considered invalid by the gateway.
201    ExternalPortZeroInvalid,
202    /// The requested mapping conflicts with a mapping assigned to another client.
203    PortInUse,
204    /// The gateway requires that the requested internal and external ports are the same.
205    SamePortValuesRequired,
206    /// The gateway only supports permanent leases (ie. a `lease_duration` of 0).
207    OnlyPermanentLeasesSupported,
208    /// The description was too long for the gateway to handle.
209    DescriptionTooLong,
210    /// Some other error occured performing the request.
211    RequestError(RequestError),
212}
213
214impl fmt::Display for GetExternalIpError {
215    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
216        match *self {
217            GetExternalIpError::ActionNotAuthorized => write!(f, "The client is not authorized to remove the port"),
218            GetExternalIpError::RequestError(ref e) => write!(f, "Request Error. {e}"),
219        }
220    }
221}
222
223impl From<io::Error> for GetExternalIpError {
224    fn from(err: io::Error) -> GetExternalIpError {
225        GetExternalIpError::RequestError(RequestError::from(err))
226    }
227}
228
229impl std::error::Error for GetExternalIpError {
230    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
231        None
232    }
233}
234
235impl fmt::Display for RemovePortError {
236    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
237        match *self {
238            RemovePortError::ActionNotAuthorized => write!(f, "The client is not authorized to remove the port"),
239            RemovePortError::NoSuchPortMapping => write!(f, "The port was not mapped"),
240            RemovePortError::RequestError(ref e) => write!(f, "Request error. {e}"),
241        }
242    }
243}
244
245impl std::error::Error for RemovePortError {
246    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
247        None
248    }
249}
250
251impl fmt::Display for AddAnyPortError {
252    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
253        match *self {
254            AddAnyPortError::ActionNotAuthorized => {
255                write!(f, "The client is not authorized to remove the port")
256            }
257            AddAnyPortError::InternalPortZeroInvalid => {
258                write!(f, "Can not add a mapping for local port 0")
259            }
260            AddAnyPortError::NoPortsAvailable => {
261                write!(f, "The gateway does not have any free ports")
262            }
263            AddAnyPortError::OnlyPermanentLeasesSupported => {
264                write!(
265                    f,
266                    "The gateway only supports permanent leases (ie. a `lease_duration` of 0),"
267                )
268            }
269            AddAnyPortError::ExternalPortInUse => {
270                write!(
271                    f,
272                    "The gateway can only map internal ports to same-numbered external ports and this external port is in use."
273                )
274            }
275            AddAnyPortError::DescriptionTooLong => {
276                write!(f, "The description was too long for the gateway to handle.")
277            }
278            AddAnyPortError::RequestError(ref e) => write!(f, "Request error. {e}"),
279        }
280    }
281}
282
283impl std::error::Error for AddAnyPortError {
284    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
285        None
286    }
287}
288
289impl fmt::Display for AddPortError {
290    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
291        match *self {
292            AddPortError::ActionNotAuthorized => write!(f, "The client is not authorized to map this port."),
293            AddPortError::InternalPortZeroInvalid => write!(f, "Can not add a mapping for local port 0"),
294            AddPortError::ExternalPortZeroInvalid => write!(
295                f,
296                "External port number 0 (any port) is considered invalid by the gateway."
297            ),
298            AddPortError::PortInUse => write!(
299                f,
300                "The requested mapping conflicts with a mapping assigned to another client."
301            ),
302            AddPortError::SamePortValuesRequired => write!(
303                f,
304                "The gateway requires that the requested internal and external ports are the same."
305            ),
306            AddPortError::OnlyPermanentLeasesSupported => write!(
307                f,
308                "The gateway only supports permanent leases (ie. a `lease_duration` of 0),"
309            ),
310            AddPortError::DescriptionTooLong => write!(f, "The description was too long for the gateway to handle."),
311            AddPortError::RequestError(ref e) => write!(f, "Request error. {e}"),
312        }
313    }
314}
315
316impl std::error::Error for AddPortError {
317    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
318        None
319    }
320}
321
322/// Errors than can occur while trying to find the gateway.
323#[derive(Debug)]
324pub enum SearchError {
325    /// Http/Hyper error
326    HttpError(attohttpc::Error),
327    /// Unable to process the response
328    InvalidResponse,
329    /// IO Error
330    IoError(io::Error),
331    /// UTF-8 decoding error
332    Utf8Error(str::Utf8Error),
333    /// XML processing error
334    XmlError(xmltree::ParseError),
335    /// When using aio_async_std feature
336    #[cfg(feature = "aio_async_std")]
337    SurfError(surf::Error),
338    /// When using the aio feature.
339    #[cfg(feature = "aio_tokio")]
340    HyperError(hyper::Error),
341    /// Error parsing URI
342    #[cfg(feature = "aio_tokio")]
343    InvalidUri(hyper::http::uri::InvalidUri),
344}
345
346impl From<attohttpc::Error> for SearchError {
347    fn from(err: attohttpc::Error) -> SearchError {
348        SearchError::HttpError(err)
349    }
350}
351
352impl From<io::Error> for SearchError {
353    fn from(err: io::Error) -> SearchError {
354        SearchError::IoError(err)
355    }
356}
357
358impl From<str::Utf8Error> for SearchError {
359    fn from(err: str::Utf8Error) -> SearchError {
360        SearchError::Utf8Error(err)
361    }
362}
363
364impl From<xmltree::ParseError> for SearchError {
365    fn from(err: xmltree::ParseError) -> SearchError {
366        SearchError::XmlError(err)
367    }
368}
369
370#[cfg(feature = "aio_async_std")]
371impl From<surf::Error> for SearchError {
372    fn from(err: surf::Error) -> SearchError {
373        SearchError::SurfError(err)
374    }
375}
376
377#[cfg(feature = "aio_tokio")]
378impl From<hyper::Error> for SearchError {
379    fn from(err: hyper::Error) -> SearchError {
380        SearchError::HyperError(err)
381    }
382}
383
384#[cfg(feature = "aio_tokio")]
385impl From<hyper::http::uri::InvalidUri> for SearchError {
386    fn from(err: hyper::http::uri::InvalidUri) -> SearchError {
387        SearchError::InvalidUri(err)
388    }
389}
390
391#[cfg(feature = "aio_async_std")]
392impl From<TimeoutError> for SearchError {
393    fn from(_err: TimeoutError) -> SearchError {
394        SearchError::IoError(io::Error::new(io::ErrorKind::TimedOut, "timer failed"))
395    }
396}
397
398#[cfg(feature = "aio_tokio")]
399impl From<Elapsed> for SearchError {
400    fn from(_err: Elapsed) -> SearchError {
401        SearchError::IoError(io::Error::new(io::ErrorKind::TimedOut, "search timed out"))
402    }
403}
404
405impl fmt::Display for SearchError {
406    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
407        match *self {
408            SearchError::HttpError(ref e) => write!(f, "HTTP error {e}"),
409            SearchError::InvalidResponse => write!(f, "Invalid response"),
410            SearchError::IoError(ref e) => write!(f, "IO error: {e}"),
411            SearchError::Utf8Error(ref e) => write!(f, "UTF-8 error: {e}"),
412            SearchError::XmlError(ref e) => write!(f, "XML error: {e}"),
413            #[cfg(feature = "aio_async_std")]
414            SearchError::SurfError(ref e) => write!(f, "Surf Error: {e}"),
415            #[cfg(feature = "aio_tokio")]
416            SearchError::HyperError(ref e) => write!(f, "Hyper Error: {e}"),
417            #[cfg(feature = "aio_tokio")]
418            SearchError::InvalidUri(ref e) => write!(f, "InvalidUri Error: {e}"),
419        }
420    }
421}
422
423impl error::Error for SearchError {
424    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
425        match *self {
426            SearchError::HttpError(ref e) => Some(e),
427            SearchError::InvalidResponse => None,
428            SearchError::IoError(ref e) => Some(e),
429            SearchError::Utf8Error(ref e) => Some(e),
430            SearchError::XmlError(ref e) => Some(e),
431            #[cfg(feature = "aio_async_std")]
432            SearchError::SurfError(ref e) => Some(e.as_ref()),
433            #[cfg(feature = "aio_tokio")]
434            SearchError::HyperError(ref e) => Some(e),
435            #[cfg(feature = "aio_tokio")]
436            SearchError::InvalidUri(ref e) => Some(e),
437        }
438    }
439}
440
441/// Errors than can occur while getting a port mapping
442#[derive(Debug)]
443pub enum GetGenericPortMappingEntryError {
444    /// The client is not authorized to perform the operation.
445    ActionNotAuthorized,
446    /// The specified array index is out of bounds.
447    SpecifiedArrayIndexInvalid,
448    /// Some other error occured performing the request.
449    RequestError(RequestError),
450}
451
452impl From<RequestError> for GetGenericPortMappingEntryError {
453    fn from(err: RequestError) -> GetGenericPortMappingEntryError {
454        match err {
455            RequestError::ErrorCode(code, _) if code == 606 => GetGenericPortMappingEntryError::ActionNotAuthorized,
456            RequestError::ErrorCode(code, _) if code == 713 => {
457                GetGenericPortMappingEntryError::SpecifiedArrayIndexInvalid
458            }
459            other => GetGenericPortMappingEntryError::RequestError(other),
460        }
461    }
462}
463
464impl fmt::Display for GetGenericPortMappingEntryError {
465    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
466        match *self {
467            GetGenericPortMappingEntryError::ActionNotAuthorized => {
468                write!(f, "The client is not authorized to look up port mappings.")
469            }
470            GetGenericPortMappingEntryError::SpecifiedArrayIndexInvalid => {
471                write!(f, "The provided index into the port mapping list is invalid.")
472            }
473            GetGenericPortMappingEntryError::RequestError(ref e) => e.fmt(f),
474        }
475    }
476}
477
478impl std::error::Error for GetGenericPortMappingEntryError {}
479
480/// An error type that emcompasses all possible errors.
481#[derive(Debug)]
482pub enum Error {
483    /// `AddAnyPortError`
484    AddAnyPortError(AddAnyPortError),
485    /// `AddPortError`
486    AddPortError(AddPortError),
487    /// `GetExternalIpError`
488    GetExternalIpError(GetExternalIpError),
489    /// `RemovePortError`
490    RemovePortError(RemovePortError),
491    /// `RequestError`
492    RequestError(RequestError),
493    /// `SearchError`
494    SearchError(SearchError),
495}
496
497/// A result type where the error is `igd::Error`.
498pub type Result<T = ()> = std::result::Result<T, Error>;
499
500impl fmt::Display for Error {
501    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
502        match *self {
503            Error::AddAnyPortError(ref e) => e.fmt(f),
504            Error::AddPortError(ref e) => e.fmt(f),
505            Error::GetExternalIpError(ref e) => e.fmt(f),
506            Error::RemovePortError(ref e) => e.fmt(f),
507            Error::RequestError(ref e) => e.fmt(f),
508            Error::SearchError(ref e) => e.fmt(f),
509        }
510    }
511}
512
513impl error::Error for Error {
514    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
515        match *self {
516            Error::AddAnyPortError(ref e) => Some(e),
517            Error::AddPortError(ref e) => Some(e),
518            Error::GetExternalIpError(ref e) => Some(e),
519            Error::RemovePortError(ref e) => Some(e),
520            Error::RequestError(ref e) => Some(e),
521            Error::SearchError(ref e) => Some(e),
522        }
523    }
524}
525
526impl From<AddAnyPortError> for Error {
527    fn from(err: AddAnyPortError) -> Error {
528        Error::AddAnyPortError(err)
529    }
530}
531
532impl From<AddPortError> for Error {
533    fn from(err: AddPortError) -> Error {
534        Error::AddPortError(err)
535    }
536}
537
538impl From<GetExternalIpError> for Error {
539    fn from(err: GetExternalIpError) -> Error {
540        Error::GetExternalIpError(err)
541    }
542}
543
544impl From<RemovePortError> for Error {
545    fn from(err: RemovePortError) -> Error {
546        Error::RemovePortError(err)
547    }
548}
549
550impl From<RequestError> for Error {
551    fn from(err: RequestError) -> Error {
552        Error::RequestError(err)
553    }
554}
555
556impl From<SearchError> for Error {
557    fn from(err: SearchError) -> Error {
558        Error::SearchError(err)
559    }
560}