internet 0.1.0

Network library for rust
Documentation
//!

use crate::{Buf, BufError, BufMut, BufResult, ietf::igmp::Checksum, ietf::ipv4::Address};

/// IGMPv3 Membership Query mapping following [Section 4.1].
///
/// [Section 4.1]: https://datatracker.ietf.org/doc/html/rfc3376#section-4.1
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct QueryMapping<T: Buf> {
    buffer: T,
}

impl<T: Buf> QueryMapping<T> {
    /// Creates a new query mapping.
    pub fn new(buffer: T) -> Self {
        Self { buffer }
    }

    /// Consumes the mapping and returns the underlying buffer.
    pub fn into_inner(self) -> T {
        self.buffer
    }

    /// Returns a reference to the underlying buffer.
    pub fn as_inner(&self) -> &T {
        &self.buffer
    }

    /// Reads the message type.
    pub fn read_type(&self) -> u8 {
        unsafe { (self.buffer.get_u16_be_unchecked(0) >> 8) as u8 }
    }

    /// Reads the max response code.
    pub fn read_max_response_code(&self) -> u8 {
        unsafe { (self.buffer.get_u16_be_unchecked(0) & 0xff) as u8 }
    }

    /// Reads the checksum.
    pub fn read_checksum(&self) -> Checksum {
        unsafe { Checksum(self.buffer.get_u16_be_unchecked(2)) }
    }

    /// Reads the group address.
    pub fn read_group_address(&self) -> Address {
        let hi = unsafe { self.buffer.get_u16_be_unchecked(4) };
        let lo = unsafe { self.buffer.get_u16_be_unchecked(6) };
        Address::from([
            (hi >> 8) as u8,
            (hi & 0xff) as u8,
            (lo >> 8) as u8,
            (lo & 0xff) as u8,
        ])
    }

    /// Reads the Suppress Router-Side Processing flag.
    pub fn read_s_flag(&self) -> bool {
        unsafe { ((self.buffer.get_u16_be_unchecked(8) >> 8) & 0x08) != 0 }
    }

    /// Reads the Querier's Robustness Variable.
    pub fn read_qrv(&self) -> u8 {
        unsafe { ((self.buffer.get_u16_be_unchecked(8) >> 8) & 0x07) as u8 }
    }

    /// Reads the Querier's Query Interval Code.
    pub fn read_qqic(&self) -> u8 {
        unsafe { (self.buffer.get_u16_be_unchecked(8) & 0xff) as u8 }
    }

    /// Reads the number of sources.
    pub fn read_number_of_sources(&self) -> u16 {
        unsafe { self.buffer.get_u16_be_unchecked(10) }
    }
}

impl<T: BufMut> QueryMapping<T> {
    /// Writes the message type.
    pub fn write_type(&mut self, val: u8) -> BufResult<()> {
        if self.buffer.length() < 2 {
            return Err(BufError::BufferTooSmall);
        }
        let mut word = unsafe { self.buffer.get_u16_be_unchecked(0) };
        word = (word & 0x00ff) | ((val as u16) << 8);
        unsafe { self.buffer.set_u16_be_unchecked(0, word) }
        Ok(())
    }

    /// Writes the max response code.
    pub fn write_max_response_code(&mut self, val: u8) -> BufResult<()> {
        if self.buffer.length() < 2 {
            return Err(BufError::BufferTooSmall);
        }
        let mut word = unsafe { self.buffer.get_u16_be_unchecked(0) };
        word = (word & 0xff00) | (val as u16);
        unsafe { self.buffer.set_u16_be_unchecked(0, word) }
        Ok(())
    }

    /// Writes the checksum.
    pub fn write_checksum(&mut self, checksum: Checksum) -> BufResult<()> {
        if self.buffer.length() < 4 {
            return Err(BufError::BufferTooSmall);
        }
        unsafe { self.buffer.set_u16_be_unchecked(2, checksum.0) }
        Ok(())
    }

    /// Writes the group address.
    pub fn write_group_address(&mut self, address: Address) -> BufResult<()> {
        if self.buffer.length() < 8 {
            return Err(BufError::BufferTooSmall);
        }
        let bytes: [u8; 4] = address.into();
        let hi = ((bytes[0] as u16) << 8) | (bytes[1] as u16);
        let lo = ((bytes[2] as u16) << 8) | (bytes[3] as u16);
        unsafe {
            self.buffer.set_u16_be_unchecked(4, hi);
            self.buffer.set_u16_be_unchecked(6, lo);
        }
        Ok(())
    }

    /// Writes the Suppress Router-Side Processing flag.
    pub fn write_s_flag(&mut self, val: bool) -> BufResult<()> {
        if self.buffer.length() < 10 {
            return Err(BufError::BufferTooSmall);
        }
        let mut word = unsafe { self.buffer.get_u16_be_unchecked(8) };
        let byte = (word >> 8) as u8;
        let new_byte = if val { byte | 0x08 } else { byte & !0x08 };
        word = ((new_byte as u16) << 8) | (word & 0x00ff);
        unsafe { self.buffer.set_u16_be_unchecked(8, word) }
        Ok(())
    }

    /// Writes the Querier's Robustness Variable.
    pub fn write_qrv(&mut self, val: u8) -> BufResult<()> {
        if self.buffer.length() < 10 {
            return Err(BufError::BufferTooSmall);
        }
        let mut word = unsafe { self.buffer.get_u16_be_unchecked(8) };
        let byte = (word >> 8) as u8;
        let new_byte = (byte & !0x07) | (val & 0x07);
        word = ((new_byte as u16) << 8) | (word & 0x00ff);
        unsafe { self.buffer.set_u16_be_unchecked(8, word) }
        Ok(())
    }

    /// Writes the Querier's Query Interval Code.
    pub fn write_qqic(&mut self, val: u8) -> BufResult<()> {
        if self.buffer.length() < 10 {
            return Err(BufError::BufferTooSmall);
        }
        let mut word = unsafe { self.buffer.get_u16_be_unchecked(8) };
        word = (word & 0xff00) | (val as u16);
        unsafe { self.buffer.set_u16_be_unchecked(8, word) }
        Ok(())
    }

    /// Writes the number of sources.
    pub fn write_number_of_sources(&mut self, val: u16) -> BufResult<()> {
        if self.buffer.length() < 12 {
            return Err(BufError::BufferTooSmall);
        }
        unsafe { self.buffer.set_u16_be_unchecked(10, val) }
        Ok(())
    }
}

/// IGMPv3 Membership Report mapping following [Section 4.2].
///
/// [Section 4.2]: https://datatracker.ietf.org/doc/html/rfc3376#section-4.2
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ReportMapping<T: Buf> {
    buffer: T,
}

impl<T: Buf> ReportMapping<T> {
    /// Creates a new report mapping.
    pub fn new(buffer: T) -> Self {
        Self { buffer }
    }

    /// Consumes the mapping and returns the underlying buffer.
    pub fn into_inner(self) -> T {
        self.buffer
    }

    /// Returns a reference to the underlying buffer.
    pub fn as_inner(&self) -> &T {
        &self.buffer
    }

    /// Reads the message type.
    pub fn read_type(&self) -> u8 {
        unsafe { (self.buffer.get_u16_be_unchecked(0) >> 8) as u8 }
    }

    /// Reads the checksum.
    pub fn read_checksum(&self) -> Checksum {
        unsafe { Checksum(self.buffer.get_u16_be_unchecked(2)) }
    }

    /// Reads the number of group records.
    pub fn read_number_of_group_records(&self) -> u16 {
        unsafe { self.buffer.get_u16_be_unchecked(6) }
    }
}

impl<T: BufMut> ReportMapping<T> {
    /// Writes the message type.
    pub fn write_type(&mut self, val: u8) -> BufResult<()> {
        if self.buffer.length() < 2 {
            return Err(BufError::BufferTooSmall);
        }
        let mut word = unsafe { self.buffer.get_u16_be_unchecked(0) };
        word = (word & 0x00ff) | ((val as u16) << 8);
        unsafe { self.buffer.set_u16_be_unchecked(0, word) }
        Ok(())
    }

    /// Writes the checksum.
    pub fn write_checksum(&mut self, checksum: Checksum) -> BufResult<()> {
        if self.buffer.length() < 4 {
            return Err(BufError::BufferTooSmall);
        }
        unsafe { self.buffer.set_u16_be_unchecked(2, checksum.0) }
        Ok(())
    }

    /// Writes the number of group records.
    pub fn write_number_of_group_records(&mut self, val: u16) -> BufResult<()> {
        if self.buffer.length() < 8 {
            return Err(BufError::BufferTooSmall);
        }
        unsafe { self.buffer.set_u16_be_unchecked(6, val) }
        Ok(())
    }
}

/// IGMPv3 Group Record mapping following [Section 4.2.4].
///
/// [Section 4.2.4]: https://datatracker.ietf.org/doc/html/rfc3376#section-4.2.4
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct GroupRecordMapping<T: Buf> {
    buffer: T,
}

impl<T: Buf> GroupRecordMapping<T> {
    /// Creates a new group record mapping.
    pub fn new(buffer: T) -> Self {
        Self { buffer }
    }

    /// Consumes the mapping and returns the underlying buffer.
    pub fn into_inner(self) -> T {
        self.buffer
    }

    /// Returns a reference to the underlying buffer.
    pub fn as_inner(&self) -> &T {
        &self.buffer
    }

    /// Reads the record type.
    pub fn read_record_type(&self) -> u8 {
        unsafe { (self.buffer.get_u16_be_unchecked(0) >> 8) as u8 }
    }

    /// Reads the auxiliary data length.
    pub fn read_aux_data_len(&self) -> u8 {
        unsafe { (self.buffer.get_u16_be_unchecked(0) & 0xff) as u8 }
    }

    /// Reads the number of sources.
    pub fn read_number_of_sources(&self) -> u16 {
        unsafe { self.buffer.get_u16_be_unchecked(2) }
    }

    /// Reads the multicast address.
    pub fn read_multicast_address(&self) -> Address {
        let hi = unsafe { self.buffer.get_u16_be_unchecked(4) };
        let lo = unsafe { self.buffer.get_u16_be_unchecked(6) };
        Address::from([
            (hi >> 8) as u8,
            (hi & 0xff) as u8,
            (lo >> 8) as u8,
            (lo & 0xff) as u8,
        ])
    }
}

impl<T: BufMut> GroupRecordMapping<T> {
    /// Writes the record type.
    pub fn write_record_type(&mut self, val: u8) -> BufResult<()> {
        if self.buffer.length() < 2 {
            return Err(BufError::BufferTooSmall);
        }
        let mut word = unsafe { self.buffer.get_u16_be_unchecked(0) };
        word = (word & 0x00ff) | ((val as u16) << 8);
        unsafe { self.buffer.set_u16_be_unchecked(0, word) }
        Ok(())
    }

    /// Writes the auxiliary data length.
    pub fn write_aux_data_len(&mut self, val: u8) -> BufResult<()> {
        if self.buffer.length() < 2 {
            return Err(BufError::BufferTooSmall);
        }
        let mut word = unsafe { self.buffer.get_u16_be_unchecked(0) };
        word = (word & 0xff00) | (val as u16);
        unsafe { self.buffer.set_u16_be_unchecked(0, word) }
        Ok(())
    }

    /// Writes the number of sources.
    pub fn write_number_of_sources(&mut self, val: u16) -> BufResult<()> {
        if self.buffer.length() < 4 {
            return Err(BufError::BufferTooSmall);
        }
        unsafe { self.buffer.set_u16_be_unchecked(2, val) }
        Ok(())
    }

    /// Writes the multicast address.
    pub fn write_multicast_address(&mut self, address: Address) -> BufResult<()> {
        if self.buffer.length() < 8 {
            return Err(BufError::BufferTooSmall);
        }
        let bytes: [u8; 4] = address.into();
        let hi = ((bytes[0] as u16) << 8) | (bytes[1] as u16);
        let lo = ((bytes[2] as u16) << 8) | (bytes[3] as u16);
        unsafe {
            self.buffer.set_u16_be_unchecked(4, hi);
            self.buffer.set_u16_be_unchecked(6, lo);
        }
        Ok(())
    }
}