neli/
err.rs

1//! This is the module that contains the error types used in `neli`
2//!
3//! There are four main types:
4//! * [`Nlmsgerr`][crate::err::Nlmsgerr] - an application error
5//! returned from netlink as a packet.
6//! * [`NlError`][crate::err::NlError] - a general netlink error
7//! wrapping application errors, serialization and deserialization
8//! errors, and other errors that occur in `neli`.
9//! * [`DeError`] - error while deserializing
10//! * [`SerError`] - error while serializing
11//!
12//! # Design decisions
13//! All errors implement [`std::error::Error`] in an attempt to allow
14//! them to be used in conjunction with [`Result`] for easier error
15//! management even at the protocol error level.
16//!
17//! As of v0.6.0, deserializing the [`NlmsghdrErr`] struct has two
18//! optional type parameters for specifying the type of the type
19//! constant and the payload. If neither of these are provided,
20//! the deserialization defaults to [`u16`] and
21//! [`Buffer`][crate::types::Buffer] respectively which work for
22//! all cases. See the `examples/` directory for a usage example.
23
24use crate as neli;
25
26use std::{
27    error::Error,
28    fmt::{self, Debug, Display},
29    io, str, string,
30};
31
32use crate::{
33    consts::nl::{NlType, NlmFFlags},
34    types::Buffer,
35    FromBytes, FromBytesWithInput, Header, Size, ToBytes, TypeSize,
36};
37
38/// A special struct that represents the contents of an error
39/// returned at the application level. Because the returned
40/// [`nl_len`][NlmsghdrErr::nl_len] cannot always determine the
41/// length of the packet (as in the case of ACKs where no payload
42/// will be returned), this data structure relies on the total
43/// packet size for deserialization.
44#[derive(Debug, PartialEq, Eq, Size, ToBytes, FromBytesWithInput, Header)]
45#[neli(header_bound = "T: TypeSize")]
46#[neli(from_bytes_bound = "T: TypeSize + FromBytes")]
47#[neli(from_bytes_bound = "P: FromBytesWithInput<Input = usize>")]
48pub struct NlmsghdrErr<T, P> {
49    /// Length of the netlink message
50    pub nl_len: u32,
51    /// Type of the netlink message
52    pub nl_type: T,
53    /// Flags indicating properties of the request or response
54    pub nl_flags: NlmFFlags,
55    /// Sequence number for netlink protocol
56    pub nl_seq: u32,
57    /// ID of the netlink destination for requests and source for
58    /// responses.
59    pub nl_pid: u32,
60    /// Payload of netlink message
61    #[neli(input = "input - Self::header_size()")]
62    pub nl_payload: P,
63}
64
65/// Struct representing netlink packets containing errors
66#[derive(Debug, PartialEq, Eq, Size, FromBytesWithInput, ToBytes, Header)]
67#[neli(from_bytes_bound = "T: NlType")]
68#[neli(from_bytes_bound = "P: FromBytesWithInput<Input = usize>")]
69pub struct Nlmsgerr<T, P> {
70    /// Error code
71    pub error: libc::c_int,
72    /// Packet header for request that failed
73    #[neli(input = "input - Self::header_size()")]
74    pub nlmsg: NlmsghdrErr<T, P>,
75}
76
77impl<T, P> Display for Nlmsgerr<T, P> {
78    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79        write!(f, "{}", io::Error::from_raw_os_error(-self.error))
80    }
81}
82
83impl<T, P> Error for Nlmsgerr<T, P>
84where
85    T: Debug,
86    P: Debug,
87{
88}
89
90macro_rules! err_from {
91    ($err:ident, $($from_err:path { $from_impl:expr }),+) => {
92        $(
93            impl From<$from_err> for $err {
94                fn from(e: $from_err) -> Self {
95                    $from_impl(e)
96                }
97            }
98        )*
99    };
100}
101
102/// General netlink error
103#[derive(Debug)]
104pub enum NlError<T = u16, P = Buffer> {
105    /// Variant for [`String`]-based messages.
106    Msg(String),
107    /// An error packet sent back by netlink.
108    Nlmsgerr(Nlmsgerr<T, P>),
109    /// A serialization error.
110    Ser(SerError),
111    /// A deserialization error.
112    De(DeError),
113    /// A wrapped error from lower in the call stack.
114    Wrapped(WrappedError),
115    /// No ack was received when
116    /// [`NlmF::Ack`][crate::consts::nl::NlmF] was specified in the
117    /// request.
118    NoAck,
119    /// The sequence number for the response did not match the
120    /// request.
121    BadSeq,
122    /// Incorrect PID socket identifier in received message.
123    BadPid,
124}
125
126impl<T, P> From<Nlmsgerr<T, P>> for NlError<T, P> {
127    fn from(err: Nlmsgerr<T, P>) -> Self {
128        NlError::Nlmsgerr(err)
129    }
130}
131
132impl<T, P> From<SerError> for NlError<T, P> {
133    fn from(err: SerError) -> Self {
134        NlError::Ser(err)
135    }
136}
137
138impl<T, P> From<DeError> for NlError<T, P> {
139    fn from(err: DeError) -> Self {
140        NlError::De(err)
141    }
142}
143
144impl<T, P> From<io::Error> for NlError<T, P> {
145    fn from(err: io::Error) -> Self {
146        NlError::Wrapped(WrappedError::IOError(err))
147    }
148}
149
150err_from!(
151    NlError,
152    WrappedError { NlError::Wrapped },
153    std::str::Utf8Error { |e| NlError::Wrapped(WrappedError::from(e)) },
154    std::string::FromUtf8Error { |e| NlError::Wrapped(WrappedError::from(e)) },
155    std::ffi::FromBytesWithNulError { |e| NlError::Wrapped(WrappedError::from(e)) }
156);
157
158impl NlError {
159    /// Create new error from a data type implementing
160    /// [`Display`][std::fmt::Display]
161    pub fn msg<D>(s: D) -> Self
162    where
163        D: Display,
164    {
165        NlError::Msg(s.to_string())
166    }
167}
168
169impl<T, P> NlError<T, P> {
170    /// Create new error from a data type implementing
171    /// [`Display`][std::fmt::Display]
172    pub fn new<D>(s: D) -> Self
173    where
174        D: Display,
175    {
176        NlError::Msg(s.to_string())
177    }
178}
179
180impl<T, P> Display for NlError<T, P>
181where
182    T: Debug,
183    P: Debug,
184{
185    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
186        match *self {
187            NlError::Msg(ref msg) => write!(f, "{}", msg),
188            NlError::Nlmsgerr(ref err) => {
189                write!(f, "Error response received from netlink: {}", err)
190            }
191            NlError::Ser(ref err) => {
192                write!(f, "Serialization error: {}", err)
193            }
194            NlError::De(ref err) => {
195                write!(f, "Deserialization error: {}", err)
196            }
197            NlError::NoAck => write!(f, "No ack received"),
198            NlError::BadSeq => write!(f, "Sequence number does not match the request"),
199            NlError::BadPid => write!(f, "PID does not match the socket"),
200            NlError::Wrapped(ref e) => write!(f, "Netlink failure due to error: {}", e),
201        }
202    }
203}
204
205impl<T, P> Error for NlError<T, P>
206where
207    T: Debug,
208    P: Debug,
209{
210}
211
212/// Serialization error
213#[derive(Debug)]
214pub enum SerError {
215    /// Abitrary error message.
216    Msg(String),
217    /// A wrapped error from lower in the call stack.
218    Wrapped(WrappedError),
219    /// The end of the buffer was reached before serialization finished.
220    UnexpectedEOB,
221    /// Serialization did not fill the buffer.
222    BufferNotFilled,
223}
224
225err_from!(
226    SerError,
227    WrappedError { SerError::Wrapped },
228    std::io::Error { |e| SerError::Wrapped(WrappedError::from(e)) },
229    std::str::Utf8Error { |e| SerError::Wrapped(WrappedError::from(e)) },
230    std::string::FromUtf8Error { |e| SerError::Wrapped(WrappedError::from(e)) },
231    std::ffi::FromBytesWithNulError { |e| SerError::Wrapped(WrappedError::from(e)) }
232);
233
234impl SerError {
235    /// Create a new error with the given message as description.
236    pub fn new<D>(msg: D) -> Self
237    where
238        D: Display,
239    {
240        SerError::Msg(msg.to_string())
241    }
242}
243
244impl Display for SerError {
245    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
246        match self {
247            SerError::Msg(ref s) => write!(f, "{}", s),
248            SerError::Wrapped(ref e) => write!(f, "Error while serializing: {}", e),
249            SerError::UnexpectedEOB => write!(
250                f,
251                "The buffer was too small for the requested serialization operation",
252            ),
253            SerError::BufferNotFilled => write!(
254                f,
255                "The number of bytes written to the buffer did not fill the \
256                 given space",
257            ),
258        }
259    }
260}
261
262impl Error for SerError {}
263
264err_from!(
265    DeError,
266    WrappedError { DeError::Wrapped },
267    std::io::Error { |e| DeError::Wrapped(WrappedError::from(e)) },
268    std::str::Utf8Error { |e| DeError::Wrapped(WrappedError::from(e)) },
269    std::string::FromUtf8Error { |e| DeError::Wrapped(WrappedError::from(e)) },
270    std::ffi::FromBytesWithNulError { |e| DeError::Wrapped(WrappedError::from(e)) }
271);
272
273/// Deserialization error
274#[derive(Debug)]
275pub enum DeError {
276    /// Abitrary error message.
277    Msg(String),
278    /// A wrapped error from lower in the call stack.
279    Wrapped(WrappedError),
280    /// The end of the buffer was reached before deserialization
281    /// finished.
282    UnexpectedEOB,
283    /// Deserialization did not fill the buffer.
284    BufferNotParsed,
285    /// A null byte was found before the end of the serialized
286    /// [`String`].
287    NullError,
288    /// A null byte was not found at the end of the serialized
289    /// [`String`].
290    NoNullError,
291}
292
293impl DeError {
294    /// Create new error from a type implementing
295    /// [`Display`][std::fmt::Display]
296    pub fn new<D>(s: D) -> Self
297    where
298        D: Display,
299    {
300        DeError::Msg(s.to_string())
301    }
302}
303
304impl Display for DeError {
305    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
306        match *self {
307            DeError::Msg(ref s) => write!(f, "{}", s),
308            DeError::UnexpectedEOB => write!(
309                f,
310                "The buffer was not large enough to complete the deserialize \
311                 operation",
312            ),
313            DeError::BufferNotParsed => write!(f, "Unparsed data left in buffer"),
314            DeError::NullError => write!(f, "A null was found before the end of the buffer"),
315            DeError::NoNullError => write!(f, "No terminating null byte was found in the buffer"),
316            DeError::Wrapped(ref e) => write!(f, "Error while deserializing: {}", e),
317        }
318    }
319}
320
321impl Error for DeError {}
322
323/// An error to wrap all system level errors in a single, higher level
324/// error.
325#[derive(Debug)]
326pub enum WrappedError {
327    /// Wrapper for [`std::io::Error`]
328    IOError(io::Error),
329    /// Wrapper for [`std::str::Utf8Error`]
330    StrUtf8Error(str::Utf8Error),
331    /// Wrapper for [`std::string::FromUtf8Error`]
332    StringUtf8Error(string::FromUtf8Error),
333    /// Wrapper for [`std::ffi::FromBytesWithNulError`]
334    FFINullError(std::ffi::FromBytesWithNulError),
335}
336
337impl Display for WrappedError {
338    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
339        match *self {
340            WrappedError::IOError(ref e) => write!(f, "Wrapped IO error: {}", e),
341            WrappedError::StrUtf8Error(ref e) => write!(f, "Wrapped &str error: {}", e),
342            WrappedError::StringUtf8Error(ref e) => write!(f, "Wrapped String error: {}", e),
343            WrappedError::FFINullError(ref e) => write!(f, "Wrapped null error: {}", e),
344        }
345    }
346}
347
348impl Error for WrappedError {}
349
350macro_rules! wrapped_err_from {
351    ($($var:ident => $from_err_name:path),*) => {
352        $(
353            impl From<$from_err_name> for WrappedError {
354                fn from(v: $from_err_name) -> Self {
355                    WrappedError::$var(v)
356                }
357            }
358        )*
359    }
360}
361
362wrapped_err_from!(
363    IOError => std::io::Error,
364    StrUtf8Error => std::str::Utf8Error,
365    StringUtf8Error => std::string::FromUtf8Error,
366    FFINullError => std::ffi::FromBytesWithNulError
367);