use std::mem::transmute;
use super::classify::{ClassifiedPacketView, ClassifyError};
use crate::{
core::view::{View, ViewConversionError},
header::{layout::ScionHeaderLayout, view::ScionHeaderView},
payload::{ProtocolNumber, scmp::view::ScmpPayloadView, udp::view::UdpDatagramView},
};
pub struct Raw;
pub struct Udp;
pub struct Scmp;
#[repr(transparent)]
pub struct ScionPacketView<T = Raw>(std::marker::PhantomData<T>, [u8]);
impl<T> ScionPacketView<T> {
#[inline]
pub fn header(&self) -> &ScionHeaderView {
unsafe {
let header_len = ScionHeaderView::from_slice_unchecked(&self.1).header_len() as usize;
ScionHeaderView::from_slice_unchecked(self.1.get_unchecked(..header_len))
}
}
#[inline]
pub fn header_mut(&mut self) -> &mut ScionHeaderView {
unsafe {
let header_len = ScionHeaderView::from_slice_unchecked(&self.1).header_len() as usize;
ScionHeaderView::from_mut_slice_unchecked(self.1.get_unchecked_mut(..header_len))
}
}
#[inline]
pub fn payload(&self) -> &[u8] {
unsafe {
let header = self.header();
let header_len = header.header_len() as usize;
let payload_len = header.payload_len() as usize;
let tail_len = self.1.len().saturating_sub(header_len);
let truncated_payload_len = std::cmp::min(payload_len, tail_len);
self.1
.get_unchecked(header_len..header_len + truncated_payload_len)
}
}
}
pub type ScionRawPacketView = ScionPacketView<Raw>;
impl View for ScionRawPacketView {
#[inline]
fn has_required_size(buf: &[u8]) -> Result<usize, ViewConversionError> {
let layout = ScionHeaderLayout::from_slice(buf)?;
let packet_len = std::cmp::min(layout.header_len + layout.payload_len, buf.len());
Ok(packet_len)
}
#[inline]
unsafe fn from_slice_unchecked(buf: &[u8]) -> &Self {
unsafe { transmute(buf) }
}
#[inline]
unsafe fn from_mut_slice_unchecked(buf: &mut [u8]) -> &mut Self {
unsafe { transmute(buf) }
}
#[inline]
unsafe fn from_boxed_unchecked(buf: Box<[u8]>) -> Box<Self> {
unsafe { transmute(buf) }
}
#[inline]
unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
&mut self.1
}
#[inline]
fn as_bytes_boxed(self: Box<Self>) -> Box<[u8]> {
unsafe { std::mem::transmute(self) }
}
#[inline]
fn as_bytes(&self) -> &[u8] {
&self.1
}
}
impl ScionRawPacketView {
#[inline]
pub fn payload_mut(&mut self) -> &mut [u8] {
unsafe {
let header = self.header();
let header_len = header.header_len() as usize;
let payload_len = header.payload_len() as usize;
let tail_len = self.1.len().saturating_sub(header_len);
let truncated_payload_len = std::cmp::min(payload_len, tail_len);
self.1
.get_unchecked_mut(header_len..header_len + truncated_payload_len)
}
}
pub fn classify(&self) -> Result<ClassifiedPacketView<'_>, ClassifyError> {
match self.header().next_header().into() {
ProtocolNumber::Udp => {
let udp =
ScionUdpPacketView::try_from_raw(self).map_err(ClassifyError::MalformedUdp)?;
Ok(ClassifiedPacketView::Udp(udp))
}
ProtocolNumber::Scmp => {
let scmp = ScionScmpPacketView::try_from_raw(self)
.map_err(ClassifyError::MalformedScmp)?;
Ok(ClassifiedPacketView::Scmp(scmp))
}
_ => Ok(ClassifiedPacketView::Other(self)),
}
}
pub fn try_into_udp(&self) -> Result<&ScionUdpPacketView, ViewConversionError> {
ScionUdpPacketView::try_from_raw(self)
}
pub fn try_into_udp_mut(&mut self) -> Result<&mut ScionUdpPacketView, ViewConversionError> {
ScionUdpPacketView::try_from_raw_mut(self)
}
pub fn try_into_udp_owned(
self: Box<Self>,
) -> Result<Box<ScionUdpPacketView>, ViewConversionError> {
ScionUdpPacketView::try_from_raw_owned(self)
}
pub fn try_into_scmp(&self) -> Result<&ScionScmpPacketView, ViewConversionError> {
ScionScmpPacketView::try_from_raw(self)
}
pub fn try_into_scmp_mut(&mut self) -> Result<&mut ScionScmpPacketView, ViewConversionError> {
ScionScmpPacketView::try_from_raw_mut(self)
}
pub fn try_into_scmp_owned(
self: Box<Self>,
) -> Result<Box<ScionScmpPacketView>, ViewConversionError> {
ScionScmpPacketView::try_from_raw_owned(self)
}
}
pub type ScionUdpPacketView = ScionPacketView<Udp>;
impl View for ScionUdpPacketView {
#[inline]
fn has_required_size(buf: &[u8]) -> Result<usize, ViewConversionError> {
let packet_len = ScionRawPacketView::has_required_size(buf)?;
let view = unsafe { ScionRawPacketView::from_slice_unchecked(buf) };
_ = UdpDatagramView::has_required_size(view.payload())?;
Ok(packet_len)
}
#[inline]
unsafe fn from_slice_unchecked(buf: &[u8]) -> &Self {
unsafe { transmute(buf) }
}
#[inline]
unsafe fn from_mut_slice_unchecked(buf: &mut [u8]) -> &mut Self {
unsafe { transmute(buf) }
}
#[inline]
unsafe fn from_boxed_unchecked(buf: Box<[u8]>) -> Box<Self> {
unsafe { transmute(buf) }
}
#[inline]
unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
&mut self.1
}
#[inline]
fn as_bytes_boxed(self: Box<Self>) -> Box<[u8]> {
unsafe { transmute(self) }
}
#[inline]
fn as_bytes(&self) -> &[u8] {
&self.1
}
}
impl ScionUdpPacketView {
pub fn try_from_raw(raw: &ScionRawPacketView) -> Result<&Self, ViewConversionError> {
let (view, _) = ScionUdpPacketView::from_slice(raw.as_bytes())?;
Ok(view)
}
pub fn try_from_raw_mut(
raw: &mut ScionRawPacketView,
) -> Result<&mut Self, ViewConversionError> {
let (view, _) = {
unsafe { ScionUdpPacketView::from_mut_slice(raw.as_bytes_mut())? }
};
Ok(view)
}
pub fn try_from_raw_owned(
raw: Box<ScionRawPacketView>,
) -> Result<Box<Self>, ViewConversionError> {
ScionUdpPacketView::from_boxed(raw.as_bytes_boxed())
}
pub fn into_raw(&self) -> &ScionRawPacketView {
unsafe { ScionRawPacketView::from_slice_unchecked(self.as_bytes()) }
}
pub fn into_raw_mut(&mut self) -> &mut ScionRawPacketView {
unsafe { ScionRawPacketView::from_mut_slice_unchecked(self.as_bytes_mut()) }
}
pub fn into_raw_owned(self: Box<Self>) -> Box<ScionRawPacketView> {
unsafe { ScionRawPacketView::from_boxed_unchecked(self.as_bytes_boxed()) }
}
pub fn udp(&self) -> &UdpDatagramView {
let (view, _) = UdpDatagramView::from_slice(self.payload())
.expect("udp payload is not large enough for a UDP header");
view
}
}
impl<'a> TryFrom<&'a ScionRawPacketView> for &'a ScionUdpPacketView {
type Error = ViewConversionError;
fn try_from(value: &'a ScionRawPacketView) -> Result<Self, Self::Error> {
ScionUdpPacketView::try_from_raw(value)
}
}
impl<'a> TryFrom<&'a mut ScionRawPacketView> for &'a mut ScionUdpPacketView {
type Error = ViewConversionError;
fn try_from(value: &'a mut ScionRawPacketView) -> Result<Self, Self::Error> {
ScionUdpPacketView::try_from_raw_mut(value)
}
}
impl TryFrom<Box<ScionRawPacketView>> for Box<ScionUdpPacketView> {
type Error = ViewConversionError;
fn try_from(value: Box<ScionRawPacketView>) -> Result<Self, Self::Error> {
ScionUdpPacketView::try_from_raw_owned(value)
}
}
impl<'a> From<&'a ScionUdpPacketView> for &'a ScionRawPacketView {
fn from(value: &'a ScionUdpPacketView) -> Self {
value.into_raw()
}
}
impl<'a> From<&'a mut ScionUdpPacketView> for &'a mut ScionRawPacketView {
fn from(value: &'a mut ScionUdpPacketView) -> Self {
value.into_raw_mut()
}
}
impl From<Box<ScionUdpPacketView>> for Box<ScionRawPacketView> {
fn from(value: Box<ScionUdpPacketView>) -> Self {
value.into_raw_owned()
}
}
pub type ScionScmpPacketView = ScionPacketView<Scmp>;
impl View for ScionScmpPacketView {
#[inline]
fn has_required_size(buf: &[u8]) -> Result<usize, ViewConversionError> {
let packet_len = ScionRawPacketView::has_required_size(buf)?;
let view = unsafe { ScionRawPacketView::from_slice_unchecked(buf) };
_ = ScmpPayloadView::has_required_size(view.payload())?;
Ok(packet_len)
}
#[inline]
unsafe fn from_slice_unchecked(buf: &[u8]) -> &Self {
unsafe { transmute(buf) }
}
#[inline]
unsafe fn from_mut_slice_unchecked(buf: &mut [u8]) -> &mut Self {
unsafe { transmute(buf) }
}
#[inline]
unsafe fn from_boxed_unchecked(buf: Box<[u8]>) -> Box<Self> {
unsafe { transmute(buf) }
}
#[inline]
unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
&mut self.1
}
#[inline]
fn as_bytes_boxed(self: Box<Self>) -> Box<[u8]> {
unsafe { transmute(self) }
}
#[inline]
fn as_bytes(&self) -> &[u8] {
&self.1
}
}
impl<'a> ScionScmpPacketView {
pub fn try_from_raw(raw: &'a ScionRawPacketView) -> Result<&'a Self, ViewConversionError> {
let (view, _) = ScionScmpPacketView::from_slice(raw.as_bytes())?;
Ok(view)
}
pub fn try_from_raw_mut(
raw: &'a mut ScionRawPacketView,
) -> Result<&'a mut Self, ViewConversionError> {
let (view, _) = {
unsafe { ScionScmpPacketView::from_mut_slice(raw.as_bytes_mut())? }
};
Ok(view)
}
pub fn try_from_raw_owned(
raw: Box<ScionRawPacketView>,
) -> Result<Box<Self>, ViewConversionError> {
ScionScmpPacketView::from_boxed(raw.as_bytes_boxed())
}
pub fn into_raw(&self) -> &ScionRawPacketView {
unsafe { ScionRawPacketView::from_slice_unchecked(self.as_bytes()) }
}
pub unsafe fn into_raw_mut(&mut self) -> &mut ScionRawPacketView {
unsafe { ScionRawPacketView::from_mut_slice_unchecked(self.as_bytes_mut()) }
}
pub fn into_raw_owned(self: Box<Self>) -> Box<ScionRawPacketView> {
unsafe { ScionRawPacketView::from_boxed_unchecked(self.as_bytes_boxed()) }
}
pub fn scmp(&self) -> &ScmpPayloadView {
let (view, _) = ScmpPayloadView::from_slice(self.payload())
.expect("scmp payload is not large enough for a SCMP header");
view
}
}
impl<'a> TryFrom<&'a ScionRawPacketView> for &'a ScionScmpPacketView {
type Error = ViewConversionError;
fn try_from(value: &'a ScionRawPacketView) -> Result<Self, Self::Error> {
ScionScmpPacketView::try_from_raw(value)
}
}
impl<'a> TryFrom<&'a mut ScionRawPacketView> for &'a mut ScionScmpPacketView {
type Error = ViewConversionError;
fn try_from(value: &'a mut ScionRawPacketView) -> Result<Self, Self::Error> {
ScionScmpPacketView::try_from_raw_mut(value)
}
}
impl TryFrom<Box<ScionRawPacketView>> for Box<ScionScmpPacketView> {
type Error = ViewConversionError;
fn try_from(value: Box<ScionRawPacketView>) -> Result<Self, Self::Error> {
ScionScmpPacketView::try_from_raw_owned(value)
}
}
impl<'a> From<&'a ScionScmpPacketView> for &'a ScionRawPacketView {
fn from(value: &'a ScionScmpPacketView) -> Self {
value.into_raw()
}
}
impl From<Box<ScionScmpPacketView>> for Box<ScionRawPacketView> {
fn from(value: Box<ScionScmpPacketView>) -> Self {
value.into_raw_owned()
}
}