fn encode_header()

in quic/s2n-quic-core/src/packet/encoding.rs [106:284]


    fn encode_header<E: Encoder>(&self, packet_number_len: PacketNumberLen, encoder: &mut E);

    /// Returns the payload for the current packet
    fn payload(&mut self) -> &mut Payload;

    /// Returns the packet number for the current packet
    fn packet_number(&self) -> PacketNumber;

    // Encodes, encrypts, and header-protects a packet into a buffer
    fn encode_packet<'a>(
        mut self,
        key: &mut K,
        header_key: &H,
        largest_acknowledged_packet_number: PacketNumber,
        min_packet_len: Option<usize>,
        mut buffer: EncoderBuffer<'a>,
    ) -> Result<(ProtectedPayload<'a>, EncoderBuffer<'a>), PacketEncodingError<'a>> {
        let packet_number = self.packet_number();

        // Truncate the packet number from the largest_acknowledged_packet_number.
        let truncated_packet_number =
            if let Some(tpn) = packet_number.truncate(largest_acknowledged_packet_number) {
                tpn
            } else {
                return Err(PacketEncodingError::PacketNumberTruncationError(buffer));
            };

        let packet_number_len = truncated_packet_number.len();

        // We need to build an estimate of how large this packet is before writing it
        let mut estimator = EncoderLenEstimator::new(buffer.remaining_capacity());

        // Start by measuring the header len
        self.encode_header(packet_number_len, &mut estimator);

        // Create a payload_len cursor so we can update it with the actual value
        // after writing the payload
        let mut payload_len_cursor = Self::PayloadLenCursor::new();

        // `encode_mut` is called here to initialize the len based on the
        // remaining buffer capacity
        payload_len_cursor.encode_mut(&mut estimator);

        // Save the header_len for later use
        let header_len = estimator.len();

        // Record the truncated_packet_number encoding size
        truncated_packet_number.encode(&mut estimator);

        // Make sure the crypto tag can be written.
        // We want to write this before the payload in the
        // estimator so the payload size hint has an accurate
        // view of remaining capacity.
        estimator.write_repeated(key.tag_len(), 0);

        //= https://www.rfc-editor.org/rfc/rfc9000#section-10.3
        //# To achieve that end,
        //# the endpoint SHOULD ensure that all packets it sends are at least 22
        //# bytes longer than the minimum connection ID length that it requests
        //# the peer to include in its packets, adding PADDING frames as
        //# necessary.
        // One additional byte is added so that a stateless reset sent in response to this packet
        // (which is required to be smaller than this packet) is large enough to be
        // indistinguishable from a valid packet.
        let minimum_packet_len = min_packet_len
            .unwrap_or(0)
            .max(stateless_reset::min_indistinguishable_packet_len(key.tag_len()) + 1);

        // Compute how much the payload will need to write to satisfy the
        // minimum_packet_len
        let minimum_payload_len = minimum_packet_len.saturating_sub(estimator.len());

        //= https://www.rfc-editor.org/rfc/rfc9001#section-5.4.2
        //# in sampling packet ciphertext for header protection,
        //# the Packet Number field is assumed to be 4 bytes long

        // Header protection sampling assumes a packet number length of 4 bytes,
        // but the actual packet number may be smaller than that, so we need to ensure
        // there is still enough payload to sample from given the actual packet number length.
        let minimum_payload_len = minimum_payload_len.max(
            PacketNumberLen::MAX_LEN - truncated_packet_number.len().bytesize()
                + header_key.sealing_sample_len(),
        );

        // Try to estimate the payload size - it may be inaccurate
        // but this provides some checks to save writing the packet
        // header
        let estimated_payload_len = self
            .payload()
            .encoding_size_hint(&estimator, minimum_payload_len);

        // The payload is not interested in writing to this packet
        if estimated_payload_len == 0 {
            return Err(PacketEncodingError::EmptyPayload(buffer));
        }

        // Use the estimated_payload_len to check if we're
        // going to have enough room for it.
        estimator.write_repeated(estimated_payload_len, 0);

        // We don't have enough room to write this packet
        if estimator.overflowed() {
            return Err(PacketEncodingError::InsufficientSpace(buffer));
        }

        // After computing the minimum length we actually start writing to the buffer

        // Now we actually encode the header
        self.encode_header(packet_number_len, &mut buffer);

        // Write the estimated payload len. This will be updated
        // with the accurate value after everything is written.
        payload_len_cursor.encode(&mut buffer);

        // Write the packet number
        truncated_packet_number.encode(&mut buffer);

        let (payload_len, inline_len, extra) = {
            // Create a temporary buffer for writing the payload
            let (header_buffer, payload_buffer) = buffer.split_mut();

            // Payloads should not be able to write into the crypto tag space
            let payload_len = payload_buffer.len() - key.tag_len();
            let payload_buffer = EncoderBuffer::new(&mut payload_buffer[..payload_len]);
            let mut payload_buffer = scatter::Buffer::new(payload_buffer);

            // Try to encode the payload into the buffer
            self.payload().encode(
                &mut payload_buffer,
                minimum_payload_len,
                header_buffer.len(),
                key.tag_len(),
            );

            // read how much was written
            let payload_len = payload_buffer.len();

            let (inline_buffer, extra) = payload_buffer.into_inner();

            // record the number of bytes that were written to the inline buffer
            let inline_len = inline_buffer.len();

            (payload_len, inline_len, extra)
        };

        // The payload didn't have anything to write so rewind the cursor
        if payload_len == 0 {
            buffer.set_position(0);
            return Err(PacketEncodingError::EmptyPayload(buffer));
        }

        // Ideally we would check that the `payload_len >= minimum_payload_len`. However, the packet
        // interceptor may rewrite the packet into something smaller. Instead of preventing that
        // here, we will rely on the `crate::transmission::Transmission` logic to ensure the
        // padding is initially written to ensure the minimum is met before interception is applied.

        // Update the payload_len cursor with the actual payload len
        let actual_payload_len = buffer.len() + payload_len + key.tag_len() - header_len;
        payload_len_cursor.update(&mut buffer, actual_payload_len);

        // Advance the buffer cursor by what the payload wrote inline. We'll recreate the scatter
        // buffer with the option extra bytes at the end.
        buffer.advance_position(inline_len);
        let buffer = scatter::Buffer::new_with_extra(buffer, extra);

        // Encrypt the written payload. Note that the tag is appended to the
        // buffer in the `encrypt` function.
        let (encrypted_payload, remaining) =
            crate::crypto::encrypt(key, packet_number, packet_number_len, header_len, buffer)
                .expect("encryption should always work");

        // Protect the packet
        let protected_payload = crate::crypto::protect(header_key, encrypted_payload)
            .expect("header protection should always work");

        // SUCCESS!!!

        Ok((protected_payload, remaining))
    }