mod header;
mod read;
mod reader;
mod referred;
mod rules;
mod write;
pub use header::*;
pub use reader::*;
pub use referred::*;
pub use rules::*;
use crate::*;
use std::marker::PhantomData;
pub trait BlockReferredDef<B: BlockDef>: ReadBlockFromSlice + Size + Sized + Into<B> {}
pub trait BlockDef:
ReadBlockFrom + ReadFrom + TryReadFrom + TryReadFromBuffered + WriteTo + WriteVectoredTo + Size
{
}
pub trait PayloadInnerDef:
Sized
+ PayloadSchema
+ PayloadEncode
+ PayloadHooks
+ PayloadEncodeReferred
+ PayloadSize
+ PayloadCrc
+ PayloadSignature
+ WriteMutTo
+ WriteVectoredMutTo
{
}
pub trait PayloadDef<Inner: PayloadInnerDef>:
ExtractPayloadFrom<Inner> + TryExtractPayloadFrom<Inner> + TryExtractPayloadFromBuffered<Inner>
{
}
pub enum LookInStatus<T> {
Accepted(usize, T),
Denied(usize),
NotEnoughData(usize),
}
pub struct PacketDef<B: BlockDef, P: PayloadDef<Inner>, Inner: PayloadInnerDef> {
pub blocks: Vec<B>,
pub payload: Option<Inner>,
_pi: PhantomData<P>,
}
impl<B: BlockDef, P: PayloadDef<Inner>, Inner: PayloadInnerDef> PayloadSchema
for PacketDef<B, P, Inner>
{
type Context<'a> = <Inner as PayloadSchema>::Context<'a>;
}
impl<B: BlockDef, P: PayloadDef<Inner>, Inner: PayloadInnerDef> PacketDef<B, P, Inner> {
pub fn new(blocks: Vec<B>, payload: Option<Inner>) -> Self {
Self {
blocks,
payload,
_pi: PhantomData,
}
}
pub fn filtered<R, BR>(
reader: &mut R,
rules: &RulesDef<B, BR, P, Inner>,
ctx: &mut <Inner as PayloadSchema>::Context<'_>,
) -> Result<LookInStatus<PacketDef<B, P, Inner>>, Error>
where
R: std::io::Read + std::io::Seek,
BR: BlockReferredDef<B>,
Self: Sized,
{
let header = <PacketHeader as ReadFrom>::read(reader)?;
let mut read = 0usize;
let mut blocks = Vec::new();
let blocks_len = header.blocks_len as usize;
if blocks_len > 0 {
let mut blocks_buffer = vec![0; blocks_len];
reader.read_exact(&mut blocks_buffer)?;
loop {
let blk =
<BR as ReadBlockFromSlice>::read_from_slice(&blocks_buffer[read..], false)?;
read += blk.size() as usize;
blocks.push(blk);
if read == blocks_len {
break;
}
}
}
let packet_size = header.size as usize;
if !rules.prefilter(&blocks) {
if header.payload {
let to_skip = packet_size.saturating_sub(blocks_len);
if to_skip > 0 {
reader.seek(std::io::SeekFrom::Current(to_skip as i64))?;
}
}
return Ok(LookInStatus::Denied(packet_size));
}
let pkg = if header.payload {
let payload_header = <PayloadHeader as ReadFrom>::read(reader)?;
let payload_body_len = payload_header.payload_len();
if rules.has_payload_filter() {
let mut payload_buffer = vec![0; payload_body_len];
reader.read_exact(&mut payload_buffer)?;
if !rules.filter_payload(&payload_buffer) {
return Ok(LookInStatus::Denied(packet_size));
}
let mut payload_reader = std::io::Cursor::new(payload_buffer);
match <P as TryExtractPayloadFromBuffered<Inner>>::try_read(
&mut payload_reader,
&payload_header,
ctx,
) {
Ok(ReadStatus::Success(payload)) => PacketDef::new(
blocks.into_iter().map(|blk| blk.into()).collect::<Vec<B>>(),
Some(payload),
),
Ok(ReadStatus::NotEnoughData(needed)) => {
return Err(Error::NotEnoughData(needed as usize));
}
Err(err) => {
return Err(err);
}
}
} else {
match <P as TryExtractPayloadFrom<Inner>>::try_read(reader, &payload_header, ctx) {
Ok(ReadStatus::Success(payload)) => PacketDef::new(
blocks.into_iter().map(|blk| blk.into()).collect::<Vec<B>>(),
Some(payload),
),
Ok(ReadStatus::NotEnoughData(needed)) => {
return Err(Error::NotEnoughData(needed as usize));
}
Err(err) => {
return Err(err);
}
}
}
} else {
PacketDef::new(
blocks.into_iter().map(|blk| blk.into()).collect::<Vec<B>>(),
None,
)
};
if !rules.filter_packet(&pkg) {
Ok(LookInStatus::Denied(packet_size))
} else {
Ok(LookInStatus::Accepted(packet_size, pkg))
}
}
}
impl<B: BlockDef, P: PayloadDef<Inner>, Inner: PayloadInnerDef> Default for PacketDef<B, P, Inner> {
fn default() -> Self {
Self {
blocks: Vec::new(),
payload: None,
_pi: PhantomData,
}
}
}