| /** @file |
| * |
| * A brief file description |
| * |
| * @section license License |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #pragma once |
| |
| #include <memory> |
| #include <atomic> |
| #include <cstddef> |
| |
| #include "I_IOBuffer.h" |
| |
| #include "QUICTypes.h" |
| #include "QUICRetryIntegrityTag.h" |
| |
| #define QUIC_FIELD_OFFSET_CONNECTION_ID 1 |
| #define QUIC_FIELD_OFFSET_PACKET_NUMBER 4 |
| #define QUIC_FIELD_OFFSET_PAYLOAD 5 |
| |
| class UDPConnection; |
| |
| class QUICPacket |
| { |
| public: |
| static constexpr int MAX_INSTANCE_SIZE = 1024; |
| |
| // Token field in Initial packet could be very long. |
| static constexpr size_t MAX_PACKET_HEADER_LEN = 256; |
| |
| /** |
| * Creates a QUICPacket for sending packets |
| */ |
| QUICPacket(bool ack_eliciting, bool probing); |
| |
| virtual ~QUICPacket(); |
| |
| virtual QUICPacketType type() const = 0; |
| virtual QUICConnectionId destination_cid() const = 0; |
| virtual QUICPacketNumber packet_number() const = 0; |
| bool is_ack_eliciting() const; |
| bool is_probing_packet() const; |
| |
| // TODO These two should be pure virtual |
| virtual Ptr<IOBufferBlock> |
| header_block() const |
| { |
| return Ptr<IOBufferBlock>(); |
| }; |
| virtual Ptr<IOBufferBlock> |
| payload_block() const |
| { |
| return Ptr<IOBufferBlock>(); |
| }; |
| |
| /* |
| * Size of whole QUIC packet (header + payload + integrity check) |
| */ |
| virtual uint16_t size() const; |
| |
| /* |
| * Size of header |
| */ |
| virtual uint16_t header_size() const; |
| |
| /* |
| * Length of payload (payload + integrity check if exists) |
| */ |
| virtual uint16_t payload_length() const; |
| |
| /** |
| * Key phase |
| */ |
| virtual QUICKeyPhase key_phase() const; |
| |
| // FIXME Remove this and use IOBufferBlock instead |
| void store(uint8_t *buf, size_t *len) const; |
| |
| /***** STATIC MEMBERS *****/ |
| |
| static uint8_t calc_packet_number_len(QUICPacketNumber num, QUICPacketNumber base); |
| static bool encode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len); |
| static bool decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len, QUICPacketNumber largest_acked); |
| |
| protected: |
| QUICPacket(); |
| |
| private: |
| bool _is_ack_eliciting = false; |
| bool _is_probing_packet = false; |
| }; |
| |
| class QUICPacketR : public QUICPacket |
| { |
| public: |
| /** |
| * Creates a QUICPacket for receiving packets |
| */ |
| QUICPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to); |
| |
| virtual QUICPacketType type() const override = 0; |
| |
| UDPConnection *udp_con() const; |
| virtual const IpEndpoint &from() const; |
| virtual const IpEndpoint &to() const; |
| |
| static bool read_essential_info(Ptr<IOBufferBlock> block, QUICPacketType &type, QUICVersion &version, QUICConnectionId &dcid, |
| QUICConnectionId &scid, QUICPacketNumber &packet_number, QUICPacketNumber base_packet_number, |
| QUICKeyPhase &key_phase); |
| static bool type(QUICPacketType &type, const uint8_t *packet, size_t packet_len); |
| |
| protected: |
| Ptr<IOBufferBlock> _header_block; |
| Ptr<IOBufferBlock> _payload_block; |
| |
| private: |
| UDPConnection *_udp_con = nullptr; |
| const IpEndpoint _from = {}; |
| const IpEndpoint _to = {}; |
| }; |
| |
| using QUICPacketDeleterFunc = void (*)(QUICPacket *p); |
| using QUICPacketUPtr = std::unique_ptr<QUICPacket, QUICPacketDeleterFunc>; |
| |
| class QUICPacketDeleter |
| { |
| public: |
| static void |
| delete_null_packet(QUICPacket *packet) |
| { |
| ink_assert(packet == nullptr); |
| } |
| |
| static void |
| delete_dont_free(QUICPacket *packet) |
| { |
| packet->~QUICPacket(); |
| } |
| |
| static void |
| delete_packet_new(QUICPacket *packet) |
| { |
| delete packet; |
| } |
| }; |
| |
| class QUICLongHeaderPacket : public QUICPacket |
| { |
| public: |
| /** |
| * For sending packet |
| */ |
| QUICLongHeaderPacket(QUICVersion version, const QUICConnectionId &dcid, const QUICConnectionId &scid, bool ack_eliciting, |
| bool probing, bool crypto); |
| |
| QUICConnectionId source_cid() const; |
| |
| QUICConnectionId destination_cid() const override; |
| uint16_t payload_length() const override; |
| virtual QUICVersion version() const; |
| virtual bool is_crypto_packet() const; |
| |
| protected: |
| size_t _write_common_header(uint8_t *buf) const; |
| |
| Ptr<IOBufferBlock> _payload_block; |
| size_t _payload_length = 0; |
| |
| private: |
| QUICVersion _version; |
| QUICConnectionId _dcid; |
| QUICConnectionId _scid; |
| |
| bool _is_crypto_packet; |
| }; |
| |
| class QUICLongHeaderPacketR : public QUICPacketR |
| { |
| public: |
| /** |
| * For receiving packet |
| */ |
| QUICLongHeaderPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks); |
| |
| virtual ~QUICLongHeaderPacketR(){}; |
| |
| QUICConnectionId destination_cid() const override; |
| QUICConnectionId source_cid() const; |
| virtual QUICVersion version() const; |
| |
| static bool type(QUICPacketType &type, const uint8_t *packet, size_t packet_len); |
| static bool version(QUICVersion &version, const uint8_t *packet, size_t packet_len); |
| static bool key_phase(QUICKeyPhase &key_phase, const uint8_t *packet, size_t packet_len); |
| static bool length(size_t &length, uint8_t &length_field_len, size_t &length_field_offset, const uint8_t *packet, |
| size_t packet_len); |
| static bool packet_length(size_t &packet_len, const uint8_t *buf, size_t buf_len); |
| static bool packet_number_offset(size_t &pn_offset, const uint8_t *packet, size_t packet_len); |
| |
| protected: |
| QUICVersion _version; |
| QUICConnectionId _scid; |
| QUICConnectionId _dcid; |
| }; |
| |
| class QUICShortHeaderPacket : public QUICPacket |
| { |
| public: |
| /** |
| * For sending packet |
| */ |
| QUICShortHeaderPacket(const QUICConnectionId &dcid, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, |
| QUICKeyPhase key_phase, bool ack_eliciting, bool probing); |
| |
| QUICPacketType type() const override; |
| QUICKeyPhase key_phase() const override; |
| QUICPacketNumber packet_number() const override; |
| QUICConnectionId destination_cid() const override; |
| |
| uint16_t payload_length() const override; |
| Ptr<IOBufferBlock> header_block() const override; |
| Ptr<IOBufferBlock> payload_block() const override; |
| |
| void attach_payload(Ptr<IOBufferBlock> payload, bool unprotected); |
| |
| private: |
| QUICConnectionId _dcid; |
| QUICPacketNumber _packet_number; |
| QUICKeyPhase _key_phase; |
| int _packet_number_len; |
| |
| Ptr<IOBufferBlock> _payload_block; |
| size_t _payload_length; |
| }; |
| |
| class QUICShortHeaderPacketR : public QUICPacketR |
| { |
| public: |
| /** |
| * For receiving packet |
| */ |
| QUICShortHeaderPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks, |
| QUICPacketNumber base_packet_number); |
| |
| void attach_payload(Ptr<IOBufferBlock> payload, bool unprotected); |
| |
| QUICPacketType type() const override; |
| QUICKeyPhase key_phase() const override; |
| QUICPacketNumber packet_number() const override; |
| QUICConnectionId destination_cid() const override; |
| |
| Ptr<IOBufferBlock> header_block() const override; |
| Ptr<IOBufferBlock> payload_block() const override; |
| |
| static bool packet_number_offset(size_t &pn_offset, const uint8_t *packet, size_t packet_len, int dcil); |
| |
| private: |
| QUICKeyPhase _key_phase; |
| QUICPacketNumber _packet_number; |
| int _packet_number_len; |
| QUICConnectionId _dcid; |
| }; |
| |
| class QUICStatelessResetPacket : public QUICPacket |
| { |
| public: |
| /** |
| * For sending packet |
| */ |
| QUICStatelessResetPacket(QUICStatelessResetToken token, size_t maximum_size); |
| |
| QUICPacketType type() const override; |
| QUICPacketNumber packet_number() const override; |
| QUICConnectionId destination_cid() const override; |
| |
| Ptr<IOBufferBlock> header_block() const override; |
| Ptr<IOBufferBlock> payload_block() const override; |
| |
| QUICStatelessResetToken token() const; |
| |
| private: |
| QUICStatelessResetToken _token; |
| size_t _maximum_size; |
| }; |
| |
| class QUICStatelessResetPacketR : public QUICPacketR |
| { |
| public: |
| /** |
| * For receiving packet |
| */ |
| QUICStatelessResetPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks); |
| |
| QUICPacketType type() const override; |
| QUICPacketNumber packet_number() const override; |
| QUICConnectionId destination_cid() const override; |
| }; |
| |
| class QUICVersionNegotiationPacket : public QUICLongHeaderPacket |
| { |
| public: |
| /** |
| * For sending packet |
| */ |
| QUICVersionNegotiationPacket(QUICConnectionId dcid, QUICConnectionId scid, const QUICVersion versions[], int nversions); |
| |
| QUICPacketType type() const override; |
| QUICVersion version() const override; |
| QUICPacketNumber packet_number() const override; |
| uint16_t payload_length() const override; |
| |
| Ptr<IOBufferBlock> header_block() const override; |
| Ptr<IOBufferBlock> payload_block() const override; |
| |
| const QUICVersion *versions() const; |
| int nversions() const; |
| |
| private: |
| const QUICVersion *_versions; |
| int _nversions; |
| }; |
| |
| class QUICVersionNegotiationPacketR : public QUICLongHeaderPacketR |
| { |
| public: |
| /** |
| * For receiving packet |
| */ |
| QUICVersionNegotiationPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks); |
| |
| QUICPacketType type() const override; |
| QUICPacketNumber packet_number() const override; |
| QUICConnectionId destination_cid() const override; |
| |
| Ptr<IOBufferBlock> header_block() const override; |
| Ptr<IOBufferBlock> payload_block() const override; |
| |
| const QUICVersion supported_version(uint8_t index) const; |
| int nversions() const; |
| |
| private: |
| QUICConnectionId _dcid; |
| uint8_t *_versions; |
| int _nversions; |
| }; |
| |
| class QUICInitialPacket : public QUICLongHeaderPacket |
| { |
| public: |
| /** |
| * For sending packet |
| */ |
| QUICInitialPacket(QUICVersion version, const QUICConnectionId &dcid, const QUICConnectionId &scid, size_t token_len, |
| ats_unique_buf token, size_t length, QUICPacketNumber packet_number, bool ack_eliciting, bool probing, |
| bool crypto); |
| |
| QUICPacketType type() const override; |
| QUICPacketNumber packet_number() const override; |
| QUICKeyPhase key_phase() const override; |
| |
| Ptr<IOBufferBlock> header_block() const override; |
| Ptr<IOBufferBlock> payload_block() const override; |
| void attach_payload(Ptr<IOBufferBlock> payload, bool unprotected); |
| |
| private: |
| size_t _token_len = 0; |
| ats_unique_buf _token = ats_unique_buf(nullptr); |
| QUICPacketNumber _packet_number; |
| }; |
| |
| class QUICInitialPacketR : public QUICLongHeaderPacketR |
| { |
| public: |
| /** |
| * For receiving packet |
| */ |
| QUICInitialPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks, |
| QUICPacketNumber base_packet_number); |
| ~QUICInitialPacketR(); |
| |
| Ptr<IOBufferBlock> header_block() const override; |
| Ptr<IOBufferBlock> payload_block() const override; |
| void attach_payload(Ptr<IOBufferBlock> payload, bool unprotected); |
| |
| QUICPacketType type() const override; |
| QUICPacketNumber packet_number() const override; |
| QUICKeyPhase key_phase() const override; |
| |
| const QUICAddressValidationToken &token() const; |
| |
| static bool token_length(size_t &token_length, uint8_t &field_len, size_t &token_length_filed_offset, const uint8_t *packet, |
| size_t packet_len); |
| |
| protected: |
| Ptr<IOBufferBlock> _payload_block; |
| |
| private: |
| QUICPacketNumber _packet_number; |
| QUICAddressValidationToken *_token = nullptr; |
| |
| bool _parse(); |
| }; |
| |
| class QUICZeroRttPacket : public QUICLongHeaderPacket |
| { |
| public: |
| /** |
| * For sending packet |
| */ |
| QUICZeroRttPacket(QUICVersion version, const QUICConnectionId &dcid, const QUICConnectionId &scid, size_t length, |
| QUICPacketNumber packet_number, bool ack_eliciting, bool probing); |
| |
| QUICPacketType type() const override; |
| QUICPacketNumber packet_number() const override; |
| QUICKeyPhase key_phase() const override; |
| |
| Ptr<IOBufferBlock> header_block() const override; |
| Ptr<IOBufferBlock> payload_block() const override; |
| void attach_payload(Ptr<IOBufferBlock> payload, bool unprotected); |
| |
| private: |
| QUICPacketNumber _packet_number; |
| }; |
| |
| class QUICZeroRttPacketR : public QUICLongHeaderPacketR |
| { |
| public: |
| /** |
| * For receiving packet |
| */ |
| QUICZeroRttPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks, |
| QUICPacketNumber base_packet_number); |
| |
| Ptr<IOBufferBlock> header_block() const override; |
| Ptr<IOBufferBlock> payload_block() const override; |
| void attach_payload(Ptr<IOBufferBlock> payload, bool unprotected); |
| |
| QUICPacketType type() const override; |
| QUICPacketNumber packet_number() const override; |
| QUICKeyPhase key_phase() const override; |
| |
| private: |
| QUICPacketNumber _packet_number; |
| }; |
| |
| class QUICHandshakePacket : public QUICLongHeaderPacket |
| { |
| public: |
| /** |
| * For sending packet |
| */ |
| QUICHandshakePacket(QUICVersion version, const QUICConnectionId &dcid, const QUICConnectionId &scid, size_t length, |
| QUICPacketNumber packet_number, bool ack_eliciting, bool probing, bool crypto); |
| |
| QUICPacketType type() const override; |
| QUICKeyPhase key_phase() const override; |
| QUICPacketNumber packet_number() const override; |
| |
| Ptr<IOBufferBlock> header_block() const override; |
| Ptr<IOBufferBlock> payload_block() const override; |
| void attach_payload(Ptr<IOBufferBlock> payload, bool unprotected); |
| |
| private: |
| QUICPacketNumber _packet_number; |
| }; |
| |
| class QUICHandshakePacketR : public QUICLongHeaderPacketR |
| { |
| public: |
| /** |
| * For receiving packet |
| */ |
| QUICHandshakePacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks, |
| QUICPacketNumber base_packet_number); |
| |
| Ptr<IOBufferBlock> header_block() const override; |
| Ptr<IOBufferBlock> payload_block() const override; |
| void attach_payload(Ptr<IOBufferBlock> payload, bool unprotected); |
| |
| QUICPacketType type() const override; |
| QUICKeyPhase key_phase() const override; |
| QUICPacketNumber packet_number() const override; |
| |
| private: |
| QUICPacketNumber _packet_number; |
| }; |
| |
| class QUICRetryPacket : public QUICLongHeaderPacket |
| { |
| public: |
| /** |
| * For sending packet |
| */ |
| QUICRetryPacket(QUICVersion version, const QUICConnectionId &dcid, const QUICConnectionId &scid, QUICRetryToken &token); |
| |
| QUICPacketType type() const override; |
| QUICPacketNumber packet_number() const override; |
| uint16_t payload_length() const override; |
| |
| Ptr<IOBufferBlock> header_block() const override; |
| Ptr<IOBufferBlock> payload_block() const override; |
| |
| const QUICRetryToken &token() const; |
| |
| private: |
| QUICRetryToken _token; |
| |
| bool _compute_retry_integrity_tag(uint8_t *out, QUICConnectionId odcid, Ptr<IOBufferBlock> header, |
| Ptr<IOBufferBlock> payload) const; |
| }; |
| |
| class QUICRetryPacketR : public QUICLongHeaderPacketR |
| { |
| public: |
| /** |
| * For receiving packet |
| */ |
| QUICRetryPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks); |
| ~QUICRetryPacketR(); |
| |
| Ptr<IOBufferBlock> header_block() const override; |
| Ptr<IOBufferBlock> payload_block() const override; |
| |
| QUICPacketType type() const override; |
| QUICPacketNumber packet_number() const override; |
| |
| const QUICAddressValidationToken &token() const; |
| bool has_valid_tag(const QUICConnectionId &odcid) const; |
| |
| private: |
| QUICAddressValidationToken *_token = nullptr; |
| uint8_t _integrity_tag[QUICRetryIntegrityTag::LEN]; |
| Ptr<IOBufferBlock> _payload_block_without_tag; |
| }; |