use super::super::packet::header::{QuicConnectionId, QuicConnectionIdField, QuicShortHeader};
use super::QuicPacketBuildError;
pub struct QuicShortPacketBuilder<'buffer, 'input> {
destination: &'buffer mut [u8],
spin: bool,
protected_low_bits: u8,
destination_connection_id: QuicConnectionId<'input>,
protected_remainder: &'input [u8],
}
impl<'buffer, 'input> QuicShortPacketBuilder<'buffer, 'input> {
pub fn new(
destination: &'buffer mut [u8],
spin: bool,
protected_low_bits: u8,
destination_connection_id: QuicConnectionId<'input>,
protected_remainder: &'input [u8],
) -> Self {
Self {
destination,
spin,
protected_low_bits,
destination_connection_id,
protected_remainder,
}
}
pub fn build(self) -> Result<QuicShortHeader<'buffer>, QuicPacketBuildError> {
if self.protected_low_bits > 0x1f {
return Err(QuicPacketBuildError::ProtectedLowBitsOutOfRange {
maximum: 0x1f,
actual: self.protected_low_bits,
});
}
if self.destination_connection_id.len() > 20 {
return Err(QuicPacketBuildError::ConnectionIdTooLong {
field: QuicConnectionIdField::Destination,
maximum: 20,
actual: self.destination_connection_id.len(),
});
}
if self.protected_remainder.len() < 2 {
return Err(QuicPacketBuildError::ProtectedRemainderTooShort {
minimum: 2,
actual: self.protected_remainder.len(),
});
}
let destination_end = checked_add(
1,
self.destination_connection_id.len(),
"destination connection ID",
)?;
let required = checked_add(
destination_end,
self.protected_remainder.len(),
"protected remainder",
)?;
if self.destination.len() < required {
return Err(QuicPacketBuildError::BufferTooShort {
required,
available: self.destination.len(),
});
}
let destination = self.destination;
destination[0] = 0x40 | (u8::from(self.spin) << 5) | self.protected_low_bits;
destination[1..destination_end].copy_from_slice(self.destination_connection_id.as_bytes());
destination[destination_end..required].copy_from_slice(self.protected_remainder);
let bytes = &destination[..required];
Ok(QuicShortHeader::from_validated(
bytes,
bytes[0],
QuicConnectionId::new(&bytes[1..destination_end]),
&bytes[destination_end..],
))
}
}
fn checked_add(
offset: usize,
length: usize,
component: &'static str,
) -> Result<usize, QuicPacketBuildError> {
offset
.checked_add(length)
.ok_or(QuicPacketBuildError::LengthOverflow {
component,
offset,
length,
})
}