internet 0.1.0

Network library for rust
Documentation
//! IGMPv2 protocol following [RFC 2236].
//!
//! [RFC 2236]: https://datatracker.ietf.org/doc/html/rfc2236

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

/// An IGMPv2 Membership Query following [RFC 2236].
///
/// [RFC 2236]: https://datatracker.ietf.org/doc/html/rfc2236
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Query {
    /// Max Response Time in units of 1/10 second.
    pub max_response_time: u8,
    /// The Internet checksum of the entire IGMP message.
    pub checksum: Checksum,
    /// The group address being queried.
    pub group_address: Address,
}

impl Query {
    /// Type field value: 0x11.
    pub const TYPE: u8 = 0x11;
}

impl Codec for Query {
    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
        Self::TYPE.encode(writer, ())?;
        self.max_response_time.encode(writer, ())?;
        self.checksum.encode(writer, ())?;
        let addr_bytes: [u8; 4] = self.group_address.into();
        addr_bytes.encode(writer, ())
    }

    fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
        if u8::decode(reader, ())? != Self::TYPE {
            return Err(BufError::UnexpectedValue);
        }
        Ok(Self {
            max_response_time: u8::decode(reader, ())?,
            checksum: Checksum::decode(reader, ())?,
            group_address: Address::from(reader.read_array::<4>()?),
        })
    }
}

/// An IGMPv2 Membership Report following [RFC 2236].
///
/// [RFC 2236]: https://datatracker.ietf.org/doc/html/rfc2236
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Report {
    /// Reserved field, must be zero on transmission, ignored on reception.
    pub reserved: u8,
    /// The Internet checksum of the entire IGMP message.
    pub checksum: Checksum,
    /// The group address being reported.
    pub group_address: Address,
}

impl Report {
    /// Type field value: 0x16.
    pub const TYPE: u8 = 0x16;
}

impl Codec for Report {
    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
        Self::TYPE.encode(writer, ())?;
        self.reserved.encode(writer, ())?;
        self.checksum.encode(writer, ())?;
        let addr_bytes: [u8; 4] = self.group_address.into();
        addr_bytes.encode(writer, ())
    }

    fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
        if u8::decode(reader, ())? != Self::TYPE {
            return Err(BufError::UnexpectedValue);
        }
        Ok(Self {
            reserved: u8::decode(reader, ())?,
            checksum: Checksum::decode(reader, ())?,
            group_address: Address::from(reader.read_array::<4>()?),
        })
    }
}

/// An IGMPv2 Leave Group message following [RFC 2236].
///
/// [RFC 2236]: https://datatracker.ietf.org/doc/html/rfc2236
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct LeaveGroup {
    /// Reserved field, must be zero on transmission, ignored on reception.
    pub reserved: u8,
    /// The Internet checksum of the entire IGMP message.
    pub checksum: Checksum,
    /// The group address being left.
    pub group_address: Address,
}

impl LeaveGroup {
    /// Type field value: 0x17.
    pub const TYPE: u8 = 0x17;
}

impl Codec for LeaveGroup {
    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
        Self::TYPE.encode(writer, ())?;
        self.reserved.encode(writer, ())?;
        self.checksum.encode(writer, ())?;
        let addr_bytes: [u8; 4] = self.group_address.into();
        addr_bytes.encode(writer, ())
    }

    fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
        if u8::decode(reader, ())? != Self::TYPE {
            return Err(BufError::UnexpectedValue);
        }
        Ok(Self {
            reserved: u8::decode(reader, ())?,
            checksum: Checksum::decode(reader, ())?,
            group_address: Address::from(reader.read_array::<4>()?),
        })
    }
}