use std::error::Error as StdError;
use std::fmt;
use nfs3_types::rpc::{accept_stat_data, auth_stat, rejected_reply};
#[derive(Debug)]
pub enum RpcError {
Io(std::io::Error),
Xdr(nfs3_types::xdr_codec::Error),
UnexpectedCall,
Auth(auth_stat),
RpcMismatch {
low: u32,
high: u32,
},
WrongLength,
UnexpectedXid,
NotFullyParsed {
buf: Vec<u8>,
pos: u64,
},
ProgUnavail,
ProgMismatch {
low: u32,
high: u32,
},
ProcUnavail,
GarbageArgs,
FragmentedReply,
SystemErr,
}
impl fmt::Display for RpcError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Io(e) => e.fmt(f),
Self::Xdr(e) => e.fmt(f),
Self::UnexpectedCall => write!(f, "Unexpected CALL request"),
Self::Auth(stat) => write!(f, "Authentication error: {stat}"),
Self::RpcMismatch { low, high } => {
write!(f, "RPC version mismatch (supported: {low}..={high})")
}
Self::WrongLength => write!(f, "Wrong length in RPC message"),
Self::UnexpectedXid => write!(f, "Unexpected XID in RPC reply"),
Self::NotFullyParsed { .. } => write!(f, "Not fully parsed"),
Self::ProgUnavail => write!(f, "Program unavailable"),
Self::ProgMismatch { low, high } => {
write!(f, "Program mismatch (supported: {low}..={high})")
}
Self::ProcUnavail => write!(f, "Procedure unavailable"),
Self::GarbageArgs => write!(f, "Garbage arguments"),
Self::FragmentedReply => write!(f, "Fragmented replies are not supported"),
Self::SystemErr => write!(f, "System error"),
}
}
}
impl StdError for RpcError {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
Self::Io(e) => Some(e),
Self::Xdr(e) => Some(e),
_ => None,
}
}
}
impl From<std::io::Error> for RpcError {
fn from(e: std::io::Error) -> Self {
Self::Io(e)
}
}
impl From<nfs3_types::xdr_codec::Error> for RpcError {
fn from(e: nfs3_types::xdr_codec::Error) -> Self {
Self::Xdr(e)
}
}
impl From<rejected_reply> for RpcError {
fn from(e: rejected_reply) -> Self {
match e {
rejected_reply::RPC_MISMATCH { low, high } => Self::RpcMismatch { low, high },
rejected_reply::AUTH_ERROR(stat) => Self::Auth(stat),
}
}
}
impl TryFrom<accept_stat_data> for RpcError {
type Error = ();
fn try_from(value: accept_stat_data) -> Result<Self, Self::Error> {
match value {
accept_stat_data::SUCCESS => Err(()),
accept_stat_data::PROG_UNAVAIL => Ok(Self::ProgUnavail),
accept_stat_data::PROG_MISMATCH { low, high } => Ok(Self::ProgMismatch { low, high }),
accept_stat_data::PROC_UNAVAIL => Ok(Self::ProcUnavail),
accept_stat_data::GARBAGE_ARGS => Ok(Self::GarbageArgs),
accept_stat_data::SYSTEM_ERR => Ok(Self::SystemErr),
}
}
}
impl RpcError {
#[must_use]
pub const fn is_connection_reusable(&self) -> bool {
!matches!(self, Self::Io(_) | Self::FragmentedReply)
}
}