parent
538080a6f1
commit
d271f164fa
@ -0,0 +1,40 @@
|
||||
//! Capabilities (permissions) of a connection.
|
||||
use super::*;
|
||||
use std::time::Duration;
|
||||
|
||||
pub mod fail;
|
||||
pub use fail::Failures;
|
||||
|
||||
/// How lenient to be with a certain operation
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord, Copy)]
|
||||
pub enum Leniency
|
||||
{
|
||||
/// Ignore **all** malformed/missed messages.
|
||||
Ignore,
|
||||
/// Allow `n` failures before disconnecting the socket.
|
||||
Specific(Failures),
|
||||
/// Allow
|
||||
Normal,
|
||||
/// Immediately disconnect the socket on **any** malformed/missed message.
|
||||
None,
|
||||
}
|
||||
|
||||
/// A capability (permission) for a raw socket's data transmission.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum RawSockCapability
|
||||
{
|
||||
/// Process
|
||||
AllowUnsignedMessages,
|
||||
|
||||
/// Do not disconnect the socket when a malformed message is received, just ignore the message.
|
||||
SoftFail,
|
||||
|
||||
/// Throttle the number of messages to process
|
||||
RateLimit{ tx: usize, rx: usize },
|
||||
|
||||
/// The request response timeout for messages with an expected response.
|
||||
RecvRespTimeout { tx: Duration, rx: Duration },
|
||||
}
|
||||
/// A collection of `RawSockCapability`s for a specific connection.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct RawSockCapabilities;
|
@ -0,0 +1,102 @@
|
||||
//! Failure counting/capping
|
||||
use super::*;
|
||||
use std::{
|
||||
fmt, error,
|
||||
};
|
||||
|
||||
/// A measure of failures, used to track or to check failures.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord, Copy)]
|
||||
pub struct Failures
|
||||
{
|
||||
/// Number of failures happened back-to-back.
|
||||
pub seq: usize,
|
||||
/// Total number of failures over the socket's lifetime.
|
||||
///
|
||||
/// Set allowed to `0` for unlimited.
|
||||
pub total: usize,
|
||||
|
||||
/// Window of time to keep failures.
|
||||
pub window: Duration,
|
||||
/// Number of failures happened in the last `window` of time.
|
||||
pub last_window: usize,
|
||||
}
|
||||
|
||||
/// When a failure cap is exceeded, which one is exceeded; and what is the limit that is exceeded?
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum FailureCapExceeded
|
||||
{
|
||||
/// Too many sequential errors
|
||||
Sequential(usize),
|
||||
/// Too many total errors
|
||||
Total(usize),
|
||||
/// Too many errors in the refresh window
|
||||
Windowed(usize, Duration),
|
||||
}
|
||||
|
||||
impl error::Error for FailureCapExceeded{}
|
||||
impl fmt::Display for FailureCapExceeded
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
match self {
|
||||
Self::Sequential(_) => write!(f, "too many sequential errors"),
|
||||
Self::Total(_) => write!(f, "too many total errors"),
|
||||
Self::Windowed(_, _) => write!(f, "too many errors in refresh window"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FailureCapExceeded
|
||||
{
|
||||
/// Convert into a detailed report. (This shouldn't be shared with peer, probably.)
|
||||
pub fn into_detailed_report(self) -> eyre::Report
|
||||
{
|
||||
let rep = eyre::Report::from(&self);
|
||||
match self {
|
||||
|
||||
Self::Sequential(cap) => rep.with_section(|| cap.header("Exceeded limit")),
|
||||
Self::Total(cap) => rep.with_section(|| cap.header("Exceeded limit")),
|
||||
Self::Windowed(cap, w) => rep.with_section(|| cap.header("Exceeded limit"))
|
||||
.with_section(|| format!("{:?}", w).header("Refresh window was"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Failures
|
||||
{
|
||||
/// Default allowed failure parameters.
|
||||
pub const DEFAULT_ALLOWED: Self = Self {
|
||||
seq: 10,
|
||||
total: 65536,
|
||||
window: Duration::from_secs(10),
|
||||
last_window: 5,
|
||||
};
|
||||
|
||||
/// Has this `Failures` exceeded failure cap `other`?
|
||||
pub fn cap_check(&self, other: &Self) -> Result<(), FailureCapExceeded>
|
||||
{
|
||||
macro_rules! chk {
|
||||
($name:ident, $err:expr) => {
|
||||
if other.$name != 0 && (self.$name >= other.$name) {
|
||||
return Err($err)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
chk!(seq, FailureCapExceeded::Sequential(other.seq));
|
||||
chk!(total, FailureCapExceeded::Total(other.total));
|
||||
//debug_assert!(other.window == self.window); //TODO: Should we disallow this?
|
||||
chk!(last_window, FailureCapExceeded::Windowed(other.last_window, self.window));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Failures
|
||||
{
|
||||
#[inline]
|
||||
fn default() -> Self
|
||||
{
|
||||
Self::DEFAULT_ALLOWED
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in new issue