internet 0.1.0

Network library for rust
Documentation
//! IGMPv1 protocol following [RFC 1112].
//!
//! [RFC 1112]: https://datatracker.ietf.org/doc/html/rfc1112

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

/// An IGMPv1 Host Membership Query following [RFC 1112].
///
/// Sent by multicast routers to query the multicast reception state of neighboring hosts.
///
/// [RFC 1112]: https://datatracker.ietf.org/doc/html/rfc1112
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Query {
    /// Unused field, must be zero on generation, ignored on reception.
    pub unused: u8,
    /// The Internet checksum of the entire IGMP message.
    pub checksum: Checksum,
    /// The group address being queried.
    pub group_address: Address,
}

impl Query {
    /// Type and Version combined: 0x11.
    pub const TYPE_AND_VERSION: u8 = 0x11;
}

impl Codec for Query {
    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
        Self::TYPE_AND_VERSION.encode(writer, ())?;
        self.unused.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> {
        let type_and_version = u8::decode(reader, ())?;
        if type_and_version != Self::TYPE_AND_VERSION {
            return Err(BufError::UnexpectedValue);
        }
        Ok(Self {
            unused: u8::decode(reader, ())?,
            checksum: Checksum::decode(reader, ())?,
            group_address: Address::from(reader.read_array::<4>()?),
        })
    }
}

/// An IGMPv1 Host Membership Report following [RFC 1112].
///
/// Sent by a host to report its membership in a particular multicast group.
///
/// [RFC 1112]: https://datatracker.ietf.org/doc/html/rfc1112
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Report {
    /// Unused field, must be zero on generation, ignored on reception.
    pub unused: u8,
    /// The Internet checksum of the entire IGMP message.
    pub checksum: Checksum,
    /// The group address being reported.
    pub group_address: Address,
}

impl Report {
    /// Type and Version combined: 0x12.
    pub const TYPE_AND_VERSION: u8 = 0x12;
}

impl Codec for Report {
    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
        Self::TYPE_AND_VERSION.encode(writer, ())?;
        self.unused.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> {
        let type_and_version = u8::decode(reader, ())?;
        if type_and_version != Self::TYPE_AND_VERSION {
            return Err(BufError::UnexpectedValue);
        }
        Ok(Self {
            unused: u8::decode(reader, ())?,
            checksum: Checksum::decode(reader, ())?,
            group_address: Address::from(reader.read_array::<4>()?),
        })
    }
}