use std::{
error::Error,
fmt::{self, Debug, Display},
io::{self, Cursor, ErrorKind},
str::Utf8Error,
string::FromUtf8Error,
};
use derive_builder::{Builder, UninitializedFieldError};
use getset::Getters;
use crate::{
self as neli,
consts::nl::{NlType, NlmF, NlmsgerrAttr},
genl::{AttrTypeBuilderError, GenlmsghdrBuilderError, NlattrBuilderError},
nl::{Nlmsghdr, NlmsghdrBuilderError},
rtnl::{
IfaddrmsgBuilderError, IfinfomsgBuilderError, NdaCacheinfoBuilderError, NdmsgBuilderError,
RtattrBuilderError, RtgenmsgBuilderError, RtmsgBuilderError, TcmsgBuilderError,
},
types::{Buffer, GenlBuffer},
FromBytes, FromBytesWithInput, Header, Size, ToBytes, TypeSize,
};
#[derive(Builder, Getters, Clone, Debug, PartialEq, Eq, Size, ToBytes, FromBytes)]
#[neli(header_bound = "T: TypeSize")]
#[neli(from_bytes_bound = "T: NlType")]
#[builder(pattern = "owned")]
pub struct NlmsghdrAck<T> {
#[getset(get = "pub")]
nl_len: u32,
#[getset(get = "pub")]
nl_type: T,
#[getset(get = "pub")]
nl_flags: NlmF,
#[getset(get = "pub")]
nl_seq: u32,
#[getset(get = "pub")]
nl_pid: u32,
}
impl NlmsghdrAck<u16> {
pub fn to_typed<T, P>(self) -> Result<NlmsghdrAck<T>, RouterError<T, P>>
where
T: NlType,
{
Ok(NlmsghdrAckBuilder::default()
.nl_len(self.nl_len)
.nl_type(T::from(self.nl_type))
.nl_flags(self.nl_flags)
.nl_seq(self.nl_seq)
.nl_pid(self.nl_pid)
.build()?)
}
}
#[derive(Builder, Getters, Clone, Debug, PartialEq, Eq, Size, ToBytes, FromBytes, Header)]
#[neli(header_bound = "T: TypeSize")]
#[neli(from_bytes_bound = "T: NlType + TypeSize")]
#[neli(from_bytes_bound = "P: FromBytesWithInput<Input = usize>")]
#[builder(build_fn(skip))]
#[builder(pattern = "owned")]
pub struct NlmsghdrErr<T, P> {
#[getset(get = "pub")]
#[builder(setter(skip))]
nl_len: u32,
#[getset(get = "pub")]
nl_type: T,
#[getset(get = "pub")]
nl_flags: NlmF,
#[getset(get = "pub")]
nl_seq: u32,
#[getset(get = "pub")]
nl_pid: u32,
#[neli(input = "nl_len as usize - Self::header_size()")]
#[getset(get = "pub")]
nl_payload: P,
}
impl<T, P> NlmsghdrErrBuilder<T, P>
where
T: NlType,
P: Size + FromBytesWithInput<Input = usize>,
{
pub fn build(self) -> Result<NlmsghdrErr<T, P>, NlmsghdrErrBuilderError> {
let nl_type = self.nl_type.ok_or_else(|| {
NlmsghdrErrBuilderError::from(UninitializedFieldError::new("nl_type"))
})?;
let nl_flags = self.nl_flags.unwrap_or(NlmF::empty());
let nl_seq = self.nl_seq.unwrap_or(0);
let nl_pid = self.nl_pid.unwrap_or(0);
let nl_payload = self.nl_payload.ok_or_else(|| {
NlmsghdrErrBuilderError::from(UninitializedFieldError::new("nl_payload"))
})?;
let mut nl = NlmsghdrErr {
nl_len: 0,
nl_type,
nl_flags,
nl_seq,
nl_pid,
nl_payload,
};
nl.nl_len = nl.padded_size() as u32;
Ok(nl)
}
}
impl NlmsghdrErr<u16, Buffer> {
pub fn to_typed<T, P>(self) -> Result<NlmsghdrErr<T, P>, RouterError<T, P>>
where
T: NlType,
P: Size + FromBytesWithInput<Input = usize>,
{
Ok(NlmsghdrErrBuilder::default()
.nl_type(T::from(self.nl_type))
.nl_flags(self.nl_flags)
.nl_seq(self.nl_seq)
.nl_pid(self.nl_pid)
.nl_payload(P::from_bytes_with_input(
&mut Cursor::new(self.nl_payload),
self.nl_len as usize - Self::header_size(),
)?)
.build()?)
}
}
#[derive(Builder, Getters, Clone, Debug, PartialEq, Eq, Size, FromBytesWithInput, ToBytes)]
#[neli(from_bytes_bound = "M: Size + FromBytes")]
#[builder(pattern = "owned")]
pub struct Nlmsgerr<M> {
#[builder(default = "0")]
#[getset(get = "pub")]
error: libc::c_int,
#[getset(get = "pub")]
#[neli(skip_debug)]
nlmsg: M,
#[neli(input = "input - error.padded_size() - nlmsg.padded_size()")]
#[builder(default = "GenlBuffer::new()")]
#[getset(get = "pub")]
ext_ack: GenlBuffer<NlmsgerrAttr, Buffer>,
}
impl<M> Display for Nlmsgerr<M> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", io::Error::from_raw_os_error(-self.error))
}
}
impl<M> Error for Nlmsgerr<M> where M: Debug {}
impl Nlmsgerr<NlmsghdrErr<u16, Buffer>> {
pub fn to_typed<T, P>(self) -> Result<Nlmsgerr<NlmsghdrErr<T, P>>, RouterError<T, P>>
where
T: NlType,
P: Size + FromBytesWithInput<Input = usize>,
{
Ok(NlmsgerrBuilder::default()
.error(self.error)
.nlmsg(self.nlmsg.to_typed()?)
.build()?)
}
}
impl Nlmsgerr<NlmsghdrAck<u16>> {
pub fn to_typed<T, P>(self) -> Result<Nlmsgerr<NlmsghdrAck<T>>, RouterError<T, P>>
where
T: NlType,
{
Ok(NlmsgerrBuilder::default()
.error(self.error)
.nlmsg(self.nlmsg.to_typed()?)
.build()?)
}
}
#[derive(Debug)]
#[allow(missing_docs)]
pub enum BuilderError {
#[allow(missing_docs)]
Nlmsghdr(NlmsghdrBuilderError),
#[allow(missing_docs)]
Nlmsgerr(NlmsgerrBuilderError),
#[allow(missing_docs)]
NlmsghdrErr(NlmsghdrErrBuilderError),
#[allow(missing_docs)]
Genlmsghdr(GenlmsghdrBuilderError),
#[allow(missing_docs)]
Nlattr(NlattrBuilderError),
#[allow(missing_docs)]
AttrType(AttrTypeBuilderError),
#[allow(missing_docs)]
Ifinfomsg(IfinfomsgBuilderError),
#[allow(missing_docs)]
Ifaddrmsg(IfaddrmsgBuilderError),
#[allow(missing_docs)]
Rtgenmsg(RtgenmsgBuilderError),
#[allow(missing_docs)]
Rtmsg(RtmsgBuilderError),
#[allow(missing_docs)]
Ndmsg(NdmsgBuilderError),
#[allow(missing_docs)]
NdaCacheinfo(NdaCacheinfoBuilderError),
#[allow(missing_docs)]
Tcmsg(TcmsgBuilderError),
#[allow(missing_docs)]
Rtattr(RtattrBuilderError),
#[allow(missing_docs)]
NlmsghdrAck(NlmsghdrAckBuilderError),
}
impl Error for BuilderError {}
impl Display for BuilderError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BuilderError::Nlmsghdr(err) => write!(f, "{}", err),
BuilderError::Nlmsgerr(err) => write!(f, "{}", err),
BuilderError::NlmsghdrErr(err) => write!(f, "{}", err),
BuilderError::Genlmsghdr(err) => write!(f, "{}", err),
BuilderError::Nlattr(err) => write!(f, "{}", err),
BuilderError::AttrType(err) => write!(f, "{}", err),
BuilderError::Ifinfomsg(err) => write!(f, "{}", err),
BuilderError::Ifaddrmsg(err) => write!(f, "{}", err),
BuilderError::Rtgenmsg(err) => write!(f, "{}", err),
BuilderError::Rtmsg(err) => write!(f, "{}", err),
BuilderError::Ndmsg(err) => write!(f, "{}", err),
BuilderError::NdaCacheinfo(err) => write!(f, "{}", err),
BuilderError::Tcmsg(err) => write!(f, "{}", err),
BuilderError::Rtattr(err) => write!(f, "{}", err),
BuilderError::NlmsghdrAck(err) => write!(f, "{}", err),
}
}
}
impl From<NlmsghdrBuilderError> for BuilderError {
fn from(e: NlmsghdrBuilderError) -> Self {
BuilderError::Nlmsghdr(e)
}
}
impl From<NlmsgerrBuilderError> for BuilderError {
fn from(e: NlmsgerrBuilderError) -> Self {
BuilderError::Nlmsgerr(e)
}
}
impl From<NlmsghdrErrBuilderError> for BuilderError {
fn from(e: NlmsghdrErrBuilderError) -> Self {
BuilderError::NlmsghdrErr(e)
}
}
impl From<GenlmsghdrBuilderError> for BuilderError {
fn from(e: GenlmsghdrBuilderError) -> Self {
BuilderError::Genlmsghdr(e)
}
}
impl From<NlattrBuilderError> for BuilderError {
fn from(e: NlattrBuilderError) -> Self {
BuilderError::Nlattr(e)
}
}
impl From<AttrTypeBuilderError> for BuilderError {
fn from(e: AttrTypeBuilderError) -> Self {
BuilderError::AttrType(e)
}
}
impl From<IfinfomsgBuilderError> for BuilderError {
fn from(e: IfinfomsgBuilderError) -> Self {
BuilderError::Ifinfomsg(e)
}
}
impl From<IfaddrmsgBuilderError> for BuilderError {
fn from(e: IfaddrmsgBuilderError) -> Self {
BuilderError::Ifaddrmsg(e)
}
}
impl From<RtgenmsgBuilderError> for BuilderError {
fn from(e: RtgenmsgBuilderError) -> Self {
BuilderError::Rtgenmsg(e)
}
}
impl From<RtmsgBuilderError> for BuilderError {
fn from(e: RtmsgBuilderError) -> Self {
BuilderError::Rtmsg(e)
}
}
impl From<NdmsgBuilderError> for BuilderError {
fn from(e: NdmsgBuilderError) -> Self {
BuilderError::Ndmsg(e)
}
}
impl From<NdaCacheinfoBuilderError> for BuilderError {
fn from(e: NdaCacheinfoBuilderError) -> Self {
BuilderError::NdaCacheinfo(e)
}
}
impl From<TcmsgBuilderError> for BuilderError {
fn from(e: TcmsgBuilderError) -> Self {
BuilderError::Tcmsg(e)
}
}
impl From<RtattrBuilderError> for BuilderError {
fn from(e: RtattrBuilderError) -> Self {
BuilderError::Rtattr(e)
}
}
impl From<NlmsghdrAckBuilderError> for BuilderError {
fn from(e: NlmsghdrAckBuilderError) -> Self {
BuilderError::NlmsghdrAck(e)
}
}
#[derive(Clone, Debug)]
pub enum RouterError<T, P> {
Msg(MsgError),
Io(ErrorKind),
De(DeError),
Socket(SocketError),
Nlmsgerr(Nlmsgerr<NlmsghdrErr<T, P>>),
BadSeqOrPid(Nlmsghdr<T, P>),
NoAck,
UnexpectedAck,
ClosedChannel,
}
impl<T, P> RouterError<T, P> {
pub fn new<D>(d: D) -> Self
where
D: Display,
{
RouterError::Msg(MsgError::new(d.to_string()))
}
}
impl RouterError<u16, Buffer> {
pub fn to_typed<T, P>(self) -> Result<RouterError<T, P>, RouterError<T, P>>
where
T: NlType,
P: Size + FromBytesWithInput<Input = usize>,
{
match self {
RouterError::Msg(msg) => Ok(RouterError::Msg(msg)),
RouterError::Io(kind) => Ok(RouterError::Io(kind)),
RouterError::De(err) => Ok(RouterError::De(err)),
RouterError::Socket(err) => Ok(RouterError::Socket(err)),
RouterError::Nlmsgerr(err) => Ok(RouterError::Nlmsgerr(err.to_typed()?)),
RouterError::BadSeqOrPid(msg) => Ok(RouterError::BadSeqOrPid(msg.to_typed()?)),
RouterError::NoAck => Ok(RouterError::NoAck),
RouterError::UnexpectedAck => Ok(RouterError::UnexpectedAck),
RouterError::ClosedChannel => Ok(RouterError::ClosedChannel),
}
}
}
impl<T, P> Display for RouterError<T, P>
where
T: Debug,
P: Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
RouterError::Msg(msg) => write!(f, "{}", msg),
RouterError::Io(kind) => write!(f, "IO error: {}", kind),
RouterError::De(err) => write!(f, "Deserialization failed: {}", err),
RouterError::Socket(err) => write!(f, "Socket error: {}", err),
RouterError::Nlmsgerr(msg) => {
write!(f, "Application error was returned by netlink: {:?}", msg)
}
RouterError::BadSeqOrPid(msg) => {
write!(f, "A bad sequence number or PID was received: {:?}", msg)
}
RouterError::NoAck => write!(f, "No ACK received"),
RouterError::UnexpectedAck => write!(f, "ACK received when none was expected"),
RouterError::ClosedChannel => {
write!(f, "A channel required for message processing closed")
}
}
}
}
impl<E, T, P> From<E> for RouterError<T, P>
where
BuilderError: From<E>,
{
fn from(e: E) -> Self {
RouterError::new(BuilderError::from(e).to_string())
}
}
impl<T, P> From<DeError> for RouterError<T, P> {
fn from(e: DeError) -> Self {
RouterError::De(e)
}
}
impl<T, P> From<SocketError> for RouterError<T, P> {
fn from(e: SocketError) -> Self {
RouterError::Socket(e)
}
}
impl<T, P> From<MsgError> for RouterError<T, P> {
fn from(e: MsgError) -> Self {
RouterError::Msg(e)
}
}
impl<T, P> Error for RouterError<T, P>
where
T: Debug,
P: Debug,
{
}
#[derive(Clone, Debug)]
pub enum SocketError {
Msg(MsgError),
Ser(SerError),
De(DeError),
Io(ErrorKind),
}
impl From<SerError> for SocketError {
fn from(err: SerError) -> Self {
SocketError::Ser(err)
}
}
impl From<DeError> for SocketError {
fn from(err: DeError) -> Self {
SocketError::De(err)
}
}
impl From<io::Error> for SocketError {
fn from(err: io::Error) -> Self {
SocketError::Io(err.kind())
}
}
impl<E> From<E> for SocketError
where
BuilderError: From<E>,
{
fn from(err: E) -> Self {
SocketError::new(BuilderError::from(err).to_string())
}
}
impl From<MsgError> for SocketError {
fn from(e: MsgError) -> Self {
SocketError::Msg(e)
}
}
impl SocketError {
pub fn new<D>(s: D) -> Self
where
D: Display,
{
SocketError::Msg(MsgError::new(s))
}
}
impl Display for SocketError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
SocketError::Msg(ref msg) => write!(f, "{}", msg),
SocketError::Ser(ref err) => {
write!(f, "Serialization error: {}", err)
}
SocketError::De(ref err) => {
write!(f, "Deserialization error: {}", err)
}
SocketError::Io(ref err) => {
write!(f, "IO error: {}", err)
}
}
}
}
impl Error for SocketError {}
#[derive(Clone, Debug)]
pub enum Utf8 {
#[allow(missing_docs)]
Str(Utf8Error),
#[allow(missing_docs)]
String(FromUtf8Error),
}
impl Display for Utf8 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Utf8::Str(e) => write!(f, "{}", e),
Utf8::String(e) => write!(f, "{}", e),
}
}
}
#[derive(Clone, Debug)]
pub enum SerError {
Msg(MsgError),
Io(ErrorKind),
Utf8(Utf8),
}
impl SerError {
pub fn new<D>(msg: D) -> Self
where
D: Display,
{
SerError::Msg(MsgError::new(msg))
}
}
impl Display for SerError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
SerError::Msg(ref s) => write!(f, "{}", s),
SerError::Io(ref err) => write!(f, "IO error: {}", err),
SerError::Utf8(ref err) => write!(f, "UTF error: {}", err),
}
}
}
impl Error for SerError {}
impl From<io::Error> for SerError {
fn from(err: io::Error) -> Self {
SerError::Io(err.kind())
}
}
impl From<Utf8Error> for SerError {
fn from(err: Utf8Error) -> Self {
SerError::Utf8(Utf8::Str(err))
}
}
impl From<FromUtf8Error> for SerError {
fn from(err: FromUtf8Error) -> Self {
SerError::Utf8(Utf8::String(err))
}
}
impl From<MsgError> for SerError {
fn from(e: MsgError) -> Self {
SerError::Msg(e)
}
}
#[derive(Clone, Debug)]
pub enum DeError {
Msg(MsgError),
Io(ErrorKind),
Utf8(Utf8),
InvalidInput(usize),
}
impl DeError {
pub fn new<D>(s: D) -> Self
where
D: Display,
{
DeError::Msg(MsgError::new(s))
}
}
impl Display for DeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
DeError::Msg(s) => write!(f, "{}", s),
DeError::Utf8(err) => write!(f, "UTF8 error: {}", err),
DeError::Io(err) => write!(f, "IO error: {}", err),
DeError::InvalidInput(input) => write!(f, "Invalid input was provided: {}", input),
}
}
}
impl Error for DeError {}
impl From<io::Error> for DeError {
fn from(err: io::Error) -> Self {
DeError::Io(err.kind())
}
}
impl From<Utf8Error> for DeError {
fn from(err: Utf8Error) -> Self {
DeError::Utf8(Utf8::Str(err))
}
}
impl From<FromUtf8Error> for DeError {
fn from(err: FromUtf8Error) -> Self {
DeError::Utf8(Utf8::String(err))
}
}
impl<E> From<E> for DeError
where
BuilderError: From<E>,
{
fn from(err: E) -> Self {
DeError::new(BuilderError::from(err).to_string())
}
}
impl From<MsgError> for DeError {
fn from(e: MsgError) -> Self {
DeError::Msg(e)
}
}
#[derive(Clone, Debug)]
pub struct MsgError(String);
impl MsgError {
pub fn new<D>(d: D) -> Self
where
D: Display,
{
MsgError(d.to_string())
}
}
impl Display for MsgError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl Error for MsgError {}