qinterface 0.7.0-beta.1

dquic's network interface and IO abstractions
Documentation
use bytes::{Bytes, BytesMut};
use derive_more::Deref;
use qbase::{
    error::QuicError,
    packet::{
        decrypt::{
            decrypt_packet, remove_protection_of_long_packet, remove_protection_of_short_packet,
        },
        header::long::InitialHeader,
        keys::ArcOneRttPacketKeys,
        number::{InvalidPacketNumber, PacketNumber},
    },
};
use qevent::quic::{
    PacketHeader, PacketHeaderBuilder, QuicFrame,
    transport::{PacketDropped, PacketDroppedTrigger, PacketReceived},
};
use rustls::quic::{HeaderProtectionKey, PacketKey};

#[derive(Debug, Deref)]
pub struct CipherPacket<H> {
    #[deref]
    header: H,
    payload: BytesMut,
    payload_offset: usize,
}

impl<H> CipherPacket<H>
where
    PacketHeaderBuilder: for<'a> From<&'a H>,
{
    pub fn new(header: H, payload: BytesMut, payload_offset: usize) -> Self {
        Self {
            header,
            payload,
            payload_offset,
        }
    }

    pub fn header(&self) -> &H {
        &self.header
    }

    fn qlog_header(&self) -> PacketHeader {
        PacketHeaderBuilder::from(&self.header).build()
    }

    pub fn drop_on_key_unavailable(self) {
        qevent::event!(PacketDropped {
            header: self.qlog_header(),
            raw: self.payload.freeze(),
            trigger: PacketDroppedTrigger::KeyUnavailable
        })
    }

    fn drop_on_remove_header_protection_failure(self) {
        qevent::event!(
            PacketDropped {
                header: self.qlog_header(),
                raw: self.payload.freeze(),
                trigger: PacketDroppedTrigger::DecryptionFailure
            },
            details = Map {
                reason: "remove header protection failure"
            }
        );
    }

    fn drop_on_decryption_failure(self, error: qbase::packet::error::Error, pn: u64) {
        qevent::event!(
            PacketDropped {
                header: {
                    PacketHeaderBuilder::from(&self.header)
                        .packet_number(pn)
                        .build()
                },
                raw: self.payload.freeze(),
                trigger: PacketDroppedTrigger::DecryptionFailure
            },
            details = Map {
                reason: "decryption failure",
                error: error.to_string(),
            },
        )
    }

    fn drop_on_reverse_bit_error(self, error: &qbase::packet::error::Error) {
        qevent::event!(
            PacketDropped {
                header: self.qlog_header(),
                raw: self.payload.freeze(),
                trigger: PacketDroppedTrigger::Invalid,
            },
            details = Map {
                reason: "reverse bit error",
                error: error.to_string()
            },
        )
    }

    fn drop_on_invalid_pn(self, invalid_pn: InvalidPacketNumber) {
        qevent::event!(
            PacketDropped {
                header: self.qlog_header(),
                raw: self.payload.freeze(),
                trigger: PacketDroppedTrigger::Invalid,
            },
            details = Map {
                reason: "invalid packet number",
                invalid_pn: invalid_pn.to_string()
            },
        )
    }

    pub fn payload_len(&self) -> usize {
        self.payload.len()
    }

    pub fn decrypt_long_packet(
        mut self,
        hpk: &dyn HeaderProtectionKey,
        pk: &dyn PacketKey,
        pn_decoder: impl FnOnce(PacketNumber) -> Result<u64, InvalidPacketNumber>,
    ) -> Option<Result<PlainPacket<H>, QuicError>> {
        let pkt_buf = self.payload.as_mut();
        let undecoded_pn = match remove_protection_of_long_packet(hpk, pkt_buf, self.payload_offset)
        {
            Ok(Some(undecoded_pn)) => undecoded_pn,
            Ok(None) => {
                self.drop_on_remove_header_protection_failure();
                return None;
            }
            Err(invalid_reverse_bits) => {
                self.drop_on_reverse_bit_error(&invalid_reverse_bits);
                return Some(Err(invalid_reverse_bits.into()));
            }
        };
        let decoded_pn = match pn_decoder(undecoded_pn) {
            Ok(pn) => pn,
            Err(invalid_packet_number) => {
                self.drop_on_invalid_pn(invalid_packet_number);
                return None;
            }
        };
        let body_offset = self.payload_offset + undecoded_pn.size();
        let body_length = match decrypt_packet(pk, decoded_pn, pkt_buf, body_offset) {
            Ok(body_length) => body_length,
            Err(error) => {
                self.drop_on_decryption_failure(error, decoded_pn);
                return None;
            }
        };

        Some(Ok(PlainPacket {
            header: self.header,
            plain: self.payload.freeze(),
            payload_offset: self.payload_offset,
            undecoded_pn,
            decoded_pn,
            body_len: body_length,
        }))
    }

    pub fn decrypt_short_packet(
        mut self,
        hpk: &dyn HeaderProtectionKey,
        pk: &ArcOneRttPacketKeys,
        pn_decoder: impl FnOnce(PacketNumber) -> Result<u64, InvalidPacketNumber>,
    ) -> Option<Result<PlainPacket<H>, QuicError>> {
        let pkt_buf = self.payload.as_mut();
        let (undecoded_pn, key_phase) =
            match remove_protection_of_short_packet(hpk, pkt_buf, self.payload_offset) {
                Ok(Some((undecoded, key_phase))) => (undecoded, key_phase),
                Ok(None) => {
                    self.drop_on_remove_header_protection_failure();
                    return None;
                }
                Err(invalid_reverse_bits) => {
                    self.drop_on_reverse_bit_error(&invalid_reverse_bits);
                    return Some(Err(invalid_reverse_bits.into()));
                }
            };
        let decoded_pn = match pn_decoder(undecoded_pn) {
            Ok(pn) => pn,
            Err(invalid_pn) => {
                self.drop_on_invalid_pn(invalid_pn);
                return None;
            }
        };
        let pk = pk.lock_guard().get_remote(key_phase, decoded_pn);
        let body_offset = self.payload_offset + undecoded_pn.size();
        let body_length = match decrypt_packet(pk.as_ref(), decoded_pn, pkt_buf, body_offset) {
            Ok(body_length) => body_length,
            Err(error) => {
                self.drop_on_decryption_failure(error, decoded_pn);
                return None;
            }
        };

        Some(Ok(PlainPacket {
            header: self.header,
            plain: self.payload.freeze(),
            payload_offset: self.payload_offset,
            undecoded_pn,
            decoded_pn,
            body_len: body_length,
        }))
    }
}

impl CipherPacket<InitialHeader> {
    pub fn drop_on_scid_unmatch(self) {
        qevent::event!(
            PacketDropped {
                header: self.qlog_header(),
                raw: self.payload.freeze(),
                trigger: PacketDroppedTrigger::Rejected
            },
            details = Map {
                reason: "different scid with first initial packet"
            },
        )
    }
}

#[derive(Deref)]
pub struct PlainPacket<H> {
    #[deref]
    header: H,
    decoded_pn: u64,
    undecoded_pn: PacketNumber,
    plain: Bytes,
    payload_offset: usize,
    body_len: usize,
}

impl<H> PlainPacket<H> {
    pub fn size(&self) -> usize {
        self.plain.len()
    }

    pub fn pn(&self) -> u64 {
        self.decoded_pn
    }

    pub fn payload_len(&self) -> usize {
        self.undecoded_pn.size() + self.body_len
    }

    pub fn body(&self) -> Bytes {
        let packet_offset = self.payload_offset + self.undecoded_pn.size();
        self.plain
            .slice(packet_offset..packet_offset + self.body_len)
    }

    pub fn raw_info(&self) -> qevent::RawInfo {
        qevent::build!(qevent::RawInfo {
            length: self.plain.len() as u64,
            payload_length: self.payload_len() as u64,
            data: &self.plain,
        })
    }
}

impl<H> PlainPacket<H>
where
    PacketHeaderBuilder: for<'a> From<&'a H>,
{
    pub fn qlog_header(&self) -> PacketHeader {
        let mut builder = PacketHeaderBuilder::from(&self.header);
        qevent::build! {@field builder,
            packet_number: self.decoded_pn,
            length: self.payload_len() as u16
        };
        builder.build()
    }

    pub fn drop_on_interface_not_found(self) {
        qevent::event!(
            PacketDropped {
                header: self.qlog_header(),
                raw: self.raw_info(),
                trigger: PacketDroppedTrigger::Genera
            },
            details = Map {
                reason: "interface not found"
            }
        )
    }

    pub fn drop_on_conenction_closed(self) {
        qevent::event!(
            PacketDropped {
                header: self.qlog_header(),
                raw: self.raw_info(),
                trigger: PacketDroppedTrigger::Genera
            },
            details = Map {
                reason: "connection closed"
            }
        )
    }

    pub fn log_received(&self, frames: impl Into<Vec<QuicFrame>>) {
        qevent::event!(PacketReceived {
            header: self.qlog_header(),
            frames,
            raw: self.raw_info(),
        })
    }
}