You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2020/08/13 20:27:08 UTC
[trafficserver] branch 9.0.x updated: Squashed commit of the
following: (#7110)
This is an automated email from the ASF dual-hosted git repository.
zwoop pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/9.0.x by this push:
new 7105dcd Squashed commit of the following: (#7110)
7105dcd is described below
commit 7105dcdb8aa8b7be15788d89cd929d1c601d7db8
Author: Masakazu Kitajo <ma...@apache.org>
AuthorDate: Fri Aug 14 05:25:44 2020 +0900
Squashed commit of the following: (#7110)
Merges -29 patches from QUIC branch to master, for inclusion with ATS 9.0.x release.
(cherry picked from commit e6bd4d13d3f8cff1af8e869f02f5fc4260d3cf4a)
---
doc/admin-guide/files/records.config.en.rst | 4 +-
include/ts/apidefs.h.in | 2 +
include/tscore/ink_inet.h | 2 +
iocore/net/P_QUICNetVConnection.h | 35 +-
iocore/net/P_QUICPacketHandler.h | 2 +-
iocore/net/QUICNetProcessor.cc | 2 +-
iocore/net/QUICNetVConnection.cc | 181 +++++---
iocore/net/QUICPacketHandler.cc | 85 ++--
iocore/net/quic/Makefile.am | 2 +-
iocore/net/quic/Mock.h | 107 ++++-
iocore/net/quic/QUICAckFrameCreator.cc | 8 +-
iocore/net/quic/QUICAckFrameCreator.h | 2 +-
iocore/net/quic/QUICAddrVerifyState.cc | 2 +-
iocore/net/quic/QUICAddrVerifyState.h | 2 +-
iocore/net/quic/QUICBidirectionalStream.cc | 4 +-
iocore/net/quic/QUICConfig.cc | 20 +-
iocore/net/quic/QUICConfig.h | 5 +-
iocore/net/quic/QUICCongestionController.h | 38 +-
iocore/net/quic/QUICConnection.h | 24 +-
iocore/net/quic/QUICContext.cc | 8 +-
iocore/net/quic/QUICContext.h | 5 +-
iocore/net/quic/QUICDebugNames.cc | 28 +-
iocore/net/quic/QUICFrame.cc | 12 -
iocore/net/quic/QUICFrame.h | 14 -
iocore/net/quic/QUICFrameDispatcher.cc | 8 +-
iocore/net/quic/QUICHandshake.cc | 76 ++-
iocore/net/quic/QUICHandshake.h | 13 +-
iocore/net/quic/QUICHandshakeProtocol.h | 2 +-
iocore/net/quic/QUICKeyGenerator.cc | 32 +-
iocore/net/quic/QUICKeyGenerator.h | 6 +-
iocore/net/quic/QUICLossDetector.cc | 507 +++++++++++----------
iocore/net/quic/QUICLossDetector.h | 144 ++----
iocore/net/quic/QUICNewRenoCongestionController.cc | 173 +++----
iocore/net/quic/QUICNewRenoCongestionController.h | 81 ++++
iocore/net/quic/QUICPacket.cc | 21 +-
iocore/net/quic/QUICPacket.h | 4 +-
iocore/net/quic/QUICPacketFactory.cc | 15 +-
iocore/net/quic/QUICPacketFactory.h | 6 +-
iocore/net/quic/QUICRetryIntegrityTag.cc | 21 +-
iocore/net/quic/QUICRetryIntegrityTag.h | 16 +-
iocore/net/quic/QUICStream.h | 3 +
iocore/net/quic/QUICTLS.cc | 6 +-
iocore/net/quic/QUICTLS.h | 2 +-
iocore/net/quic/QUICTLS_boringssl.cc | 15 +-
iocore/net/quic/QUICTLS_openssl.cc | 8 +-
iocore/net/quic/QUICTransportParameters.cc | 105 +++--
iocore/net/quic/QUICTransportParameters.h | 24 +-
iocore/net/quic/QUICTypes.cc | 48 +-
iocore/net/quic/QUICTypes.h | 74 ++-
iocore/net/quic/qlog/QLogListener.h | 2 +-
iocore/net/quic/test/test_QUICAckFrameCreator.cc | 2 +-
iocore/net/quic/test/test_QUICHandshakeProtocol.cc | 36 +-
iocore/net/quic/test/test_QUICKeyGenerator.cc | 14 +-
iocore/net/quic/test/test_QUICLossDetector.cc | 183 ++++----
iocore/net/quic/test/test_QUICPacket.cc | 27 +-
iocore/net/quic/test/test_QUICPacketFactory.cc | 11 +-
.../quic/test/test_QUICPacketHeaderProtector.cc | 18 +-
iocore/net/quic/test/test_QUICStreamManager.cc | 16 +-
.../net/quic/test/test_QUICTransportParameters.cc | 24 +-
iocore/net/quic/test/test_QUICType.cc | 14 +-
iocore/net/quic/test/test_QUICVersionNegotiator.cc | 19 +-
lib/records/RecHttp.cc | 75 +--
mgmt/RecordsConfig.cc | 4 +-
proxy/http/HttpProxyServerMain.cc | 6 +
proxy/http3/Http3Session.cc | 66 ++-
proxy/http3/Http3Session.h | 10 +-
proxy/http3/Http3SessionAccept.cc | 8 +-
src/traffic_quic/quic_client.cc | 4 +-
src/tscore/ink_inet.cc | 8 +-
69 files changed, 1551 insertions(+), 1000 deletions(-)
diff --git a/doc/admin-guide/files/records.config.en.rst b/doc/admin-guide/files/records.config.en.rst
index f964497..1a1c0b4 100644
--- a/doc/admin-guide/files/records.config.en.rst
+++ b/doc/admin-guide/files/records.config.en.rst
@@ -4064,13 +4064,13 @@ removed in the future without prior notice.
This is just for debugging. Do not change it from the default value unless
you really understand what this is.
-.. ts:cv:: CONFIG proxy.config.quic.congestion_control.initial_window_scale INT 10
+.. ts:cv:: CONFIG proxy.config.quic.congestion_control.initial_window INT 12000
:reloadable:
This is just for debugging. Do not change it from the default value unless
you really understand what this is.
-.. ts:cv:: CONFIG proxy.config.quic.congestion_control.minimum_window_scale INT 2
+.. ts:cv:: CONFIG proxy.config.quic.congestion_control.minimum_window INT 2400
:reloadable:
This is just for debugging. Do not change it from the default value unless
diff --git a/include/ts/apidefs.h.in b/include/ts/apidefs.h.in
index b2bf281..5707335 100644
--- a/include/ts/apidefs.h.in
+++ b/include/ts/apidefs.h.in
@@ -1232,7 +1232,9 @@ extern tsapi const char *const TS_ALPN_PROTOCOL_HTTP_1_0;
extern tsapi const char *const TS_ALPN_PROTOCOL_HTTP_1_1;
extern tsapi const char *const TS_ALPN_PROTOCOL_HTTP_2_0;
extern tsapi const char *const TS_ALPN_PROTOCOL_HTTP_3;
+extern tsapi const char *const TS_ALPN_PROTOCOL_HTTP_3_D27;
extern tsapi const char *const TS_ALPN_PROTOCOL_HTTP_QUIC;
+extern tsapi const char *const TS_ALPN_PROTOCOL_HTTP_QUIC_D27;
extern tsapi int TS_ALPN_PROTOCOL_INDEX_HTTP_0_9;
extern tsapi int TS_ALPN_PROTOCOL_INDEX_HTTP_1_0;
diff --git a/include/tscore/ink_inet.h b/include/tscore/ink_inet.h
index efd67c0..8c9ccaf 100644
--- a/include/tscore/ink_inet.h
+++ b/include/tscore/ink_inet.h
@@ -61,6 +61,8 @@ extern const std::string_view IP_PROTO_TAG_HTTP_1_1;
extern const std::string_view IP_PROTO_TAG_HTTP_2_0;
extern const std::string_view IP_PROTO_TAG_HTTP_QUIC;
extern const std::string_view IP_PROTO_TAG_HTTP_3;
+extern const std::string_view IP_PROTO_TAG_HTTP_QUIC_D27;
+extern const std::string_view IP_PROTO_TAG_HTTP_3_D27;
struct IpAddr; // forward declare.
diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h
index 484ea45..f04f32d 100644
--- a/iocore/net/P_QUICNetVConnection.h
+++ b/iocore/net/P_QUICNetVConnection.h
@@ -147,10 +147,11 @@ class QUICNetVConnection : public UnixNetVConnection,
public:
QUICNetVConnection();
~QUICNetVConnection();
- void init(QUICConnectionId peer_cid, QUICConnectionId original_cid, UDPConnection *, QUICPacketHandler *,
+ void init(QUICVersion version, QUICConnectionId peer_cid, QUICConnectionId original_cid, UDPConnection *, QUICPacketHandler *,
QUICResetTokenTable *rtable);
- void init(QUICConnectionId peer_cid, QUICConnectionId original_cid, QUICConnectionId first_cid, UDPConnection *,
- QUICPacketHandler *, QUICResetTokenTable *rtable, QUICConnectionTable *ctable);
+ void init(QUICVersion version, QUICConnectionId peer_cid, QUICConnectionId original_cid, QUICConnectionId first_cid,
+ QUICConnectionId retry_cid, UDPConnection *, QUICPacketHandler *, QUICResetTokenTable *rtable,
+ QUICConnectionTable *ctable);
// accept new conn_id
int acceptEvent(int event, Event *e);
@@ -199,13 +200,20 @@ public:
QUICConnectionId peer_connection_id() const override;
QUICConnectionId original_connection_id() const override;
QUICConnectionId first_connection_id() const override;
+ QUICConnectionId retry_source_connection_id() const override;
+ QUICConnectionId initial_source_connection_id() const override;
QUICConnectionId connection_id() const override;
std::string_view cids() const override;
const QUICFiveTuple five_tuple() const override;
uint32_t pmtu() const override;
NetVConnectionContext_t direction() const override;
+ QUICVersion negotiated_version() const override;
std::string_view negotiated_application_name() const override;
bool is_closed() const override;
+ bool is_at_anti_amplification_limit() const override;
+ bool is_address_validation_completed() const override;
+ bool is_handshake_completed() const override;
+ bool has_keys_for(QUICPacketNumberSpace space) const override;
// QUICConnection (QUICFrameHandler)
std::vector<QUICFrameType> interests() override;
@@ -226,17 +234,20 @@ private:
QUICConfig::scoped_config _quic_config;
- QUICConnectionId _peer_quic_connection_id; // dst cid in local
- QUICConnectionId _peer_old_quic_connection_id; // dst previous cid in local
- QUICConnectionId _original_quic_connection_id; // dst cid of initial packet from client
- QUICConnectionId _first_quic_connection_id; // dst cid of initial packet from client that doesn't have retry token
- QUICConnectionId _quic_connection_id; // src cid in local
+ QUICConnectionId _peer_quic_connection_id; // dst cid in local
+ QUICConnectionId _peer_old_quic_connection_id; // dst previous cid in local
+ QUICConnectionId _original_quic_connection_id; // dst cid of initial packet from client
+ QUICConnectionId _first_quic_connection_id; // dst cid of initial packet from client that doesn't have retry token
+ QUICConnectionId _retry_source_connection_id; // src cid used for sending Retry packet
+ QUICConnectionId _initial_source_connection_id; // src cid used for Initial packet
+ QUICConnectionId _quic_connection_id; // src cid in local
QUICFiveTuple _five_tuple;
bool _connection_migration_initiated = false;
char _cids_data[MAX_CIDS_SIZE] = {0};
std::string_view _cids;
+ QUICVersion _initial_version;
UDPConnection *_udp_con = nullptr;
QUICPacketProtectionKeyInfo _pp_key_info;
QUICPacketHandler *_packet_handler = nullptr;
@@ -277,6 +288,8 @@ private:
uint32_t _state_closing_recv_packet_window = 1;
uint64_t _flow_control_buffer_size = 1024;
+ void _init_submodules();
+
void _schedule_packet_write_ready(bool delay = false);
void _unschedule_packet_write_ready();
void _close_packet_write_ready(Event *data);
@@ -304,9 +317,9 @@ private:
uint64_t _maximum_stream_frame_data_size();
Ptr<IOBufferBlock> _store_frame(Ptr<IOBufferBlock> parent_block, size_t &size_added, uint64_t &max_frame_size, QUICFrame &frame,
- std::vector<QUICFrameInfo> &frames);
+ std::vector<QUICSentPacketInfo::FrameInfo> &frames);
QUICPacketUPtr _packetize_frames(uint8_t *packet_buf, QUICEncryptionLevel level, uint64_t max_packet_size,
- std::vector<QUICFrameInfo> &frames);
+ std::vector<QUICSentPacketInfo::FrameInfo> &frames);
void _packetize_closing_frame();
QUICPacketUPtr _build_packet(uint8_t *packet_buf, QUICEncryptionLevel level, const Ptr<IOBufferBlock> &parent_block,
bool retransmittable, bool probing, bool crypto);
@@ -337,7 +350,9 @@ private:
QUICPacketUPtr _dequeue_recv_packet(uint8_t *packet_buf, QUICPacketCreationResult &result);
void _validate_new_path(const QUICPath &path);
+ bool _handshake_completed = false;
int _complete_handshake_if_possible();
+
void _switch_to_handshake_state();
void _switch_to_established_state();
void _switch_to_closing_state(QUICConnectionErrorUPtr error);
diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h
index 0eaae22..9428b89 100644
--- a/iocore/net/P_QUICPacketHandler.h
+++ b/iocore/net/P_QUICPacketHandler.h
@@ -87,7 +87,7 @@ protected:
private:
void _recv_packet(int event, UDPPacket *udp_packet) override;
int _stateless_retry(const uint8_t *buf, uint64_t buf_len, UDPConnection *connection, IpEndpoint from, QUICConnectionId dcid,
- QUICConnectionId scid, QUICConnectionId *original_cid);
+ QUICConnectionId scid, QUICConnectionId *original_cid, QUICConnectionId *retry_cid, QUICVersion version);
bool _send_stateless_reset(QUICConnectionId dcid, uint32_t instance_id, UDPConnection *udp_con, IpEndpoint &addr,
size_t maximum_size);
void _send_invalid_token_error(const uint8_t *initial_packet, uint64_t initial_packet_len, UDPConnection *connection,
diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc
index 2075e81..5bdaa2b 100644
--- a/iocore/net/QUICNetProcessor.cc
+++ b/iocore/net/QUICNetProcessor.cc
@@ -150,7 +150,7 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, Ne
QUICConnectionId client_dst_cid;
client_dst_cid.randomize();
// vc->init set handler of vc `QUICNetVConnection::startEvent`
- vc->init(client_dst_cid, client_dst_cid, con, packet_handler, this->_rtable);
+ vc->init(QUIC_SUPPORTED_VERSIONS[0], client_dst_cid, client_dst_cid, con, packet_handler, this->_rtable);
packet_handler->init(vc);
// Connection ID will be changed
diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc
index faf052f..ba8cf74 100644
--- a/iocore/net/QUICNetVConnection.cc
+++ b/iocore/net/QUICNetVConnection.cc
@@ -37,6 +37,8 @@
#include "QUICMultiCertConfigLoader.h"
#include "QUICTLS.h"
+#include "QUICNewRenoCongestionController.h"
+
#include "QUICStats.h"
#include "QUICGlobals.h"
#include "QUICDebugNames.h"
@@ -57,6 +59,7 @@ static constexpr uint8_t QUANTUM_TEST_VALUE[1200] = {'Q'};
#define QUICConVVVDebug(fmt, ...) Debug("vvv_quic_net", "[%s] " fmt, this->cids().data(), ##__VA_ARGS__)
#define QUICFCDebug(fmt, ...) Debug("quic_flow_ctrl", "[%s] " fmt, this->cids().data(), ##__VA_ARGS__)
+#define QUICFCVDebug(fmt, ...) Debug("v_quic_flow_ctrl", "[%s] " fmt, this->cids().data(), ##__VA_ARGS__)
#define QUICError(fmt, ...) \
Debug("quic_net", "[%s] " fmt, this->cids().data(), ##__VA_ARGS__); \
@@ -236,37 +239,44 @@ QUICNetVConnection::~QUICNetVConnection()
// XXX This might be called on ET_UDP thread
// Initialize QUICNetVC for out going connection (NET_VCONNECTION_OUT)
void
-QUICNetVConnection::init(QUICConnectionId peer_cid, QUICConnectionId original_cid, UDPConnection *udp_con,
+QUICNetVConnection::init(QUICVersion version, QUICConnectionId peer_cid, QUICConnectionId original_cid, UDPConnection *udp_con,
QUICPacketHandler *packet_handler, QUICResetTokenTable *rtable)
{
SET_HANDLER((NetVConnHandler)&QUICNetVConnection::startEvent);
+ this->_initial_version = version;
this->_udp_con = udp_con;
this->_packet_handler = packet_handler;
this->_peer_quic_connection_id = peer_cid;
this->_original_quic_connection_id = original_cid;
this->_rtable = rtable;
this->_quic_connection_id.randomize();
+ this->_initial_source_connection_id = this->_quic_connection_id;
this->_update_cids();
if (is_debug_tag_set(QUIC_DEBUG_TAG.data())) {
QUICConDebug("dcid=%s scid=%s", this->_peer_quic_connection_id.hex().c_str(), this->_quic_connection_id.hex().c_str());
}
+
+ this->_init_submodules();
}
// Initialize QUICNetVC for in coming connection (NET_VCONNECTION_IN)
void
-QUICNetVConnection::init(QUICConnectionId peer_cid, QUICConnectionId original_cid, QUICConnectionId first_cid,
- UDPConnection *udp_con, QUICPacketHandler *packet_handler, QUICResetTokenTable *rtable,
- QUICConnectionTable *ctable)
+QUICNetVConnection::init(QUICVersion version, QUICConnectionId peer_cid, QUICConnectionId original_cid, QUICConnectionId first_cid,
+ QUICConnectionId retry_cid, UDPConnection *udp_con, QUICPacketHandler *packet_handler,
+ QUICResetTokenTable *rtable, QUICConnectionTable *ctable)
{
SET_HANDLER((NetVConnHandler)&QUICNetVConnection::acceptEvent);
+ this->_initial_version = version;
this->_udp_con = udp_con;
this->_packet_handler = packet_handler;
this->_peer_quic_connection_id = peer_cid;
this->_original_quic_connection_id = original_cid;
this->_first_quic_connection_id = first_cid;
+ this->_retry_source_connection_id = retry_cid;
this->_quic_connection_id.randomize();
+ this->_initial_source_connection_id = this->_quic_connection_id;
if (ctable) {
this->_ctable = ctable;
@@ -280,6 +290,30 @@ QUICNetVConnection::init(QUICConnectionId peer_cid, QUICConnectionId original_ci
if (is_debug_tag_set(QUIC_DEBUG_TAG.data())) {
QUICConDebug("dcid=%s scid=%s", this->_peer_quic_connection_id.hex().c_str(), this->_quic_connection_id.hex().c_str());
}
+
+ this->_init_submodules();
+}
+
+void
+QUICNetVConnection::_init_submodules()
+{
+ this->_pinger = new QUICPinger();
+ this->_padder = new QUICPadder(this->netvc_context);
+ this->_path_validator = new QUICPathValidator(*this, [this](bool succeeded) {
+ if (succeeded) {
+ this->_alt_con_manager->drop_cid(this->_peer_old_quic_connection_id);
+ // FIXME This is a kind of workaround for connection migration.
+ // This PING make peer to send an ACK frame so that ATS can detect packet loss.
+ // It would be better if QUICLossDetector could detect the loss in another way.
+ this->ping();
+ }
+ });
+ this->_path_manager = new QUICPathManagerImpl(*this, *this->_path_validator);
+ this->_context = std::make_unique<QUICContext>(&this->_rtt_measure, this, &this->_pp_key_info, this->_path_manager);
+ this->_congestion_controller = new QUICNewRenoCongestionController(*_context);
+ this->_rtt_measure.init(this->_context->ld_config());
+ this->_loss_detector =
+ new QUICLossDetector(*_context, this->_congestion_controller, &this->_rtt_measure, this->_pinger, this->_padder);
}
bool
@@ -379,17 +413,6 @@ void
QUICNetVConnection::start()
{
ink_release_assert(this->thread != nullptr);
- this->_path_validator = new QUICPathValidator(*this, [this](bool succeeded) {
- if (succeeded) {
- this->_alt_con_manager->drop_cid(this->_peer_old_quic_connection_id);
- // FIXME This is a kind of workaround for connection migration.
- // This PING make peer to send an ACK frame so that ATS can detect packet loss.
- // It would be better if QUICLossDetector could detect the loss in another way.
- this->ping();
- }
- });
- this->_path_manager = new QUICPathManagerImpl(*this, *this->_path_validator);
- this->_context = std::make_unique<QUICContext>(&this->_rtt_measure, this, &this->_pp_key_info, this->_path_manager);
this->_five_tuple.update(this->local_addr, this->remote_addr, SOCK_DGRAM);
QUICPath trusted_path = {{}, {}};
// Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not
@@ -398,10 +421,10 @@ QUICNetVConnection::start()
this->_pp_key_info.set_context(QUICPacketProtectionKeyInfo::Context::SERVER);
this->_ack_frame_manager.set_ack_delay_exponent(this->_quic_config->ack_delay_exponent_in());
- this->_reset_token = QUICStatelessResetToken(this->_quic_connection_id, this->_quic_config->instance_id());
- this->_hs_protocol = this->_setup_handshake_protocol(server_cert->ssl_default);
- this->_handshake_handler =
- new QUICHandshake(this, this->_hs_protocol, this->_reset_token, this->_quic_config->stateless_retry());
+ this->_reset_token = QUICStatelessResetToken(this->_quic_connection_id, this->_quic_config->instance_id());
+ this->_hs_protocol = this->_setup_handshake_protocol(server_cert->ssl_default);
+ this->_handshake_handler = new QUICHandshake(this->_initial_version, this, this->_hs_protocol, this->_reset_token,
+ this->_quic_config->stateless_retry());
this->_ack_frame_manager.set_max_ack_delay(this->_quic_config->max_ack_delay_in());
this->_schedule_ack_manager_periodic(this->_quic_config->max_ack_delay_in());
} else {
@@ -413,7 +436,7 @@ QUICNetVConnection::start()
this->_pp_key_info.set_context(QUICPacketProtectionKeyInfo::Context::CLIENT);
this->_ack_frame_manager.set_ack_delay_exponent(this->_quic_config->ack_delay_exponent_out());
this->_hs_protocol = this->_setup_handshake_protocol(this->_quic_config->client_ssl_ctx());
- this->_handshake_handler = new QUICHandshake(this, this->_hs_protocol);
+ this->_handshake_handler = new QUICHandshake(this->_initial_version, this, this->_hs_protocol);
this->_handshake_handler->start(tp_config, &this->_packet_factory, this->_quic_config->vn_exercise_enabled());
this->_handshake_handler->do_handshake();
this->_ack_frame_manager.set_max_ack_delay(this->_quic_config->max_ack_delay_out());
@@ -426,12 +449,6 @@ QUICNetVConnection::start()
this->_frame_dispatcher = new QUICFrameDispatcher(this);
// Create frame handlers
- this->_pinger = new QUICPinger();
- this->_padder = new QUICPadder(this->netvc_context);
- this->_rtt_measure.init(this->_context->ld_config());
- this->_congestion_controller = new QUICNewRenoCongestionController(*_context);
- this->_loss_detector =
- new QUICLossDetector(*_context, this->_congestion_controller, &this->_rtt_measure, this->_pinger, this->_padder);
this->_frame_dispatcher->add_handler(this->_loss_detector);
this->_remote_flow_controller = new QUICRemoteConnectionFlowController(UINT64_MAX);
@@ -597,6 +614,18 @@ QUICNetVConnection::first_connection_id() const
}
QUICConnectionId
+QUICNetVConnection::retry_source_connection_id() const
+{
+ return this->_retry_source_connection_id;
+}
+
+QUICConnectionId
+QUICNetVConnection::initial_source_connection_id() const
+{
+ return this->_initial_source_connection_id;
+}
+
+QUICConnectionId
QUICNetVConnection::connection_id() const
{
return this->_quic_connection_id;
@@ -671,6 +700,7 @@ void
QUICNetVConnection::handle_received_packet(UDPPacket *packet)
{
this->_packet_recv_queue.enqueue(packet);
+ this->_loss_detector->on_datagram_received();
}
void
@@ -1077,6 +1107,44 @@ QUICNetVConnection::is_closed() const
return this->handler == reinterpret_cast<NetVConnHandler>(&QUICNetVConnection::state_connection_closed);
}
+bool
+QUICNetVConnection::is_at_anti_amplification_limit() const
+{
+ return !this->_verified_state.is_verified() || this->_verified_state.windows() == 0;
+}
+
+bool
+QUICNetVConnection::is_address_validation_completed() const
+{
+ return this->_verified_state.is_verified();
+}
+
+bool
+QUICNetVConnection::is_handshake_completed() const
+{
+ return this->_handshake_completed;
+}
+
+bool
+QUICNetVConnection::has_keys_for(QUICPacketNumberSpace space) const
+{
+ switch (space) {
+ case QUICPacketNumberSpace::INITIAL:
+ return this->_pp_key_info.is_decryption_key_available(QUICKeyPhase::INITIAL) &&
+ this->_pp_key_info.is_encryption_key_available(QUICKeyPhase::INITIAL);
+ case QUICPacketNumberSpace::HANDSHAKE:
+ return this->_pp_key_info.is_decryption_key_available(QUICKeyPhase::HANDSHAKE) &&
+ this->_pp_key_info.is_encryption_key_available(QUICKeyPhase::HANDSHAKE);
+ case QUICPacketNumberSpace::APPLICATION_DATA:
+ return (this->_pp_key_info.is_decryption_key_available(QUICKeyPhase::PHASE_0) &&
+ this->_pp_key_info.is_encryption_key_available(QUICKeyPhase::PHASE_0)) ||
+ (this->_pp_key_info.is_decryption_key_available(QUICKeyPhase::PHASE_1) &&
+ this->_pp_key_info.is_encryption_key_available(QUICKeyPhase::PHASE_1));
+ default:
+ return false;
+ }
+}
+
QUICPacketNumber
QUICNetVConnection::_largest_acked_packet_number(QUICEncryptionLevel level) const
{
@@ -1085,6 +1153,12 @@ QUICNetVConnection::_largest_acked_packet_number(QUICEncryptionLevel level) cons
return this->_loss_detector->largest_acked_packet_number(index);
}
+QUICVersion
+QUICNetVConnection::negotiated_version() const
+{
+ return this->_handshake_handler->negotiated_version();
+}
+
std::string_view
QUICNetVConnection::negotiated_application_name() const
{
@@ -1114,6 +1188,7 @@ QUICNetVConnection::_state_handshake_process_packet(const QUICPacket &packet)
error = this->_state_handshake_process_handshake_packet(static_cast<const QUICHandshakePacketR &>(packet));
if (this->_pp_key_info.is_decryption_key_available(QUICKeyPhase::INITIAL) && this->netvc_context == NET_VCONNECTION_IN) {
this->_pp_key_info.drop_keys(QUICKeyPhase::INITIAL);
+ this->_loss_detector->on_packet_number_space_discarded(QUICPacketNumberSpace::INITIAL);
this->_minimum_encryption_level = QUICEncryptionLevel::HANDSHAKE;
}
break;
@@ -1208,6 +1283,8 @@ QUICNetVConnection::_state_handshake_process_initial_packet(const QUICInitialPac
this->_frame_dispatcher->add_handler(this->_alt_con_manager);
}
+ this->_handshake_handler->update(packet);
+
// on client side, _handshake_handler is already started. Just process packet like _state_handshake_process_handshake_packet()
error = this->_recv_and_ack(packet);
}
@@ -1246,6 +1323,7 @@ QUICNetVConnection::_state_handshake_process_retry_packet(const QUICRetryPacketR
// discard all transport state
this->_handshake_handler->reset();
+ this->_handshake_handler->update(packet);
this->_packet_factory.reset();
this->_loss_detector->reset();
@@ -1254,7 +1332,7 @@ QUICNetVConnection::_state_handshake_process_retry_packet(const QUICRetryPacketR
// Initialize Key Materials with peer CID. Because peer CID is DCID of (second) INITIAL packet from client which reply to RETRY
// packet from server
- this->_hs_protocol->initialize_key_materials(this->_peer_quic_connection_id);
+ this->_hs_protocol->initialize_key_materials(this->_peer_quic_connection_id, packet.version());
// start handshake over
this->_handshake_handler->do_handshake();
@@ -1447,8 +1525,8 @@ QUICNetVConnection::_state_common_send_packet()
max_packet_size = std::min(max_packet_size, this->_verified_state.windows());
}
- QUICPacketInfoUPtr packet_info = std::make_unique<QUICPacketInfo>();
- QUICPacketUPtr packet = this->_packetize_frames(packet_buf, level, max_packet_size, packet_info->frames);
+ QUICSentPacketInfoUPtr packet_info = std::make_unique<QUICSentPacketInfo>();
+ QUICPacketUPtr packet = this->_packetize_frames(packet_buf, level, max_packet_size, packet_info->frames);
if (packet) {
// trigger callback
@@ -1457,12 +1535,7 @@ QUICNetVConnection::_state_common_send_packet()
packet_info->packet_number = packet->packet_number();
packet_info->time_sent = Thread::get_hrtime();
packet_info->ack_eliciting = packet->is_ack_eliciting();
- if (packet->type() == QUICPacketType::PROTECTED) {
- packet_info->is_crypto_packet = false;
- } else {
- packet_info->is_crypto_packet = static_cast<QUICLongHeaderPacket &>(*packet).is_crypto_packet();
- }
- packet_info->in_flight = true;
+ packet_info->in_flight = true;
if (packet_info->ack_eliciting) {
packet_info->sent_bytes = packet->size();
} else {
@@ -1488,12 +1561,13 @@ QUICNetVConnection::_state_common_send_packet()
ink_assert(!"failed to protect buffer");
}
- QUICConDebug("[TX] %s packet #%" PRIu64 " size=%zu", QUICDebugNames::packet_type(packet->type()), packet->packet_number(),
- len);
+ QUICConVDebug("[TX] %s packet #%" PRIu64 " size=%zu", QUICDebugNames::packet_type(packet->type()), packet->packet_number(),
+ len);
if (this->_pp_key_info.is_encryption_key_available(QUICKeyPhase::INITIAL) && packet->type() == QUICPacketType::HANDSHAKE &&
this->netvc_context == NET_VCONNECTION_OUT) {
this->_pp_key_info.drop_keys(QUICKeyPhase::INITIAL);
+ this->_loss_detector->on_packet_number_space_discarded(QUICPacketNumberSpace::INITIAL);
this->_minimum_encryption_level = QUICEncryptionLevel::HANDSHAKE;
}
@@ -1542,7 +1616,7 @@ QUICNetVConnection::_state_closing_send_packet()
Ptr<IOBufferBlock>
QUICNetVConnection::_store_frame(Ptr<IOBufferBlock> parent_block, size_t &size_added, uint64_t &max_frame_size, QUICFrame &frame,
- std::vector<QUICFrameInfo> &frames)
+ std::vector<QUICSentPacketInfo::FrameInfo> &frames)
{
Ptr<IOBufferBlock> new_block = frame.to_io_buffer_block(max_frame_size);
@@ -1565,7 +1639,7 @@ QUICNetVConnection::_store_frame(Ptr<IOBufferBlock> parent_block, size_t &size_a
if (is_debug_tag_set(QUIC_DEBUG_TAG.data())) {
char msg[1024];
frame.debug_msg(msg, sizeof(msg));
- QUICConDebug("[TX] | %s", msg);
+ QUICConVDebug("[TX] | %s", msg);
}
frames.emplace_back(frame.id(), frame.generated_by());
@@ -1578,7 +1652,7 @@ QUICNetVConnection::_store_frame(Ptr<IOBufferBlock> parent_block, size_t &size_a
QUICPacketUPtr
QUICNetVConnection::_packetize_frames(uint8_t *packet_buf, QUICEncryptionLevel level, uint64_t max_packet_size,
- std::vector<QUICFrameInfo> &frames)
+ std::vector<QUICSentPacketInfo::FrameInfo> &frames)
{
QUICPacketUPtr packet = QUICPacketFactory::create_null_packet();
if (max_packet_size <= MAX_PACKET_OVERHEAD) {
@@ -1634,8 +1708,8 @@ QUICNetVConnection::_packetize_frames(uint8_t *packet_buf, QUICEncryptionLevel l
probing |= frame->is_probing_frame();
if (frame->is_flow_controlled()) {
int ret = this->_remote_flow_controller->update(this->_stream_manager->total_offset_sent());
- QUICFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(),
- this->_remote_flow_controller->current_limit());
+ QUICFCVDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(),
+ this->_remote_flow_controller->current_limit());
ink_assert(ret == 0);
}
last_block = this->_store_frame(last_block, size_added, max_frame_size, *frame, frames);
@@ -1690,7 +1764,7 @@ QUICNetVConnection::_packetize_closing_frame()
size_t size_added = 0;
uint64_t max_frame_size = static_cast<uint64_t>(max_size);
- std::vector<QUICFrameInfo> frames;
+ std::vector<QUICSentPacketInfo::FrameInfo> frames;
Ptr<IOBufferBlock> first_block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
Ptr<IOBufferBlock> last_block = first_block;
first_block->alloc(iobuffer_size_to_index(0, BUFFER_SIZE_INDEX_32K));
@@ -1736,16 +1810,16 @@ QUICNetVConnection::_recv_and_ack(const QUICPacketR &packet, bool *has_non_probi
if (is_flow_controlled) {
int ret = this->_local_flow_controller->update(this->_stream_manager->total_offset_received());
- QUICFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(),
- this->_local_flow_controller->current_limit());
+ QUICFCVDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(),
+ this->_local_flow_controller->current_limit());
if (ret != 0) {
return std::make_unique<QUICConnectionError>(QUICTransErrorCode::FLOW_CONTROL_ERROR);
}
this->_local_flow_controller->forward_limit(this->_stream_manager->total_reordered_bytes() + this->_flow_control_buffer_size);
- QUICFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(),
- this->_local_flow_controller->current_limit());
+ QUICFCVDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(),
+ this->_local_flow_controller->current_limit());
}
this->_ack_frame_manager.update(level, packet_num, size, ack_only);
@@ -1890,11 +1964,11 @@ QUICNetVConnection::_dequeue_recv_packet(uint8_t *packet_buf, QUICPacketCreation
switch (packet->type()) {
case QUICPacketType::VERSION_NEGOTIATION:
case QUICPacketType::RETRY:
- QUICConDebug("[RX] %s packet size=%u", QUICDebugNames::packet_type(packet->type()), packet->size());
+ QUICConVDebug("[RX] %s packet size=%u", QUICDebugNames::packet_type(packet->type()), packet->size());
break;
default:
- QUICConDebug("[RX] %s packet #%" PRIu64 " size=%u header_len=%u payload_len=%u", QUICDebugNames::packet_type(packet->type()),
- packet->packet_number(), packet->size(), packet->header_size(), packet->payload_length());
+ QUICConVDebug("[RX] %s packet #%" PRIu64 " size=%u header_len=%u payload_len=%u", QUICDebugNames::packet_type(packet->type()),
+ packet->packet_number(), packet->size(), packet->header_size(), packet->payload_length());
break;
}
break;
@@ -2022,11 +2096,14 @@ QUICNetVConnection::_complete_handshake_if_possible()
this->_init_flow_control_params(this->_handshake_handler->local_transport_parameters(),
this->_handshake_handler->remote_transport_parameters());
- // PN space doesn't matter but seems like this is the way to pick the LossDetector for 0-RTT and Short packet
uint64_t ack_delay_exponent =
this->_handshake_handler->remote_transport_parameters()->getAsUInt(QUICTransportParameterId::ACK_DELAY_EXPONENT);
this->_loss_detector->update_ack_delay_exponent(ack_delay_exponent);
+ uint64_t max_ack_delay =
+ this->_handshake_handler->remote_transport_parameters()->getAsUInt(QUICTransportParameterId::MAX_ACK_DELAY);
+ this->_rtt_measure.set_max_ack_delay(max_ack_delay);
+
const uint8_t *reset_token;
uint16_t reset_token_len;
reset_token = this->_handshake_handler->remote_transport_parameters()->getAsBytes(QUICTransportParameterId::STATELESS_RESET_TOKEN,
@@ -2037,6 +2114,8 @@ QUICNetVConnection::_complete_handshake_if_possible()
this->_start_application();
+ this->_handshake_completed = true;
+
return 0;
}
diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc
index 7c91351..4a69065 100644
--- a/iocore/net/QUICPacketHandler.cc
+++ b/iocore/net/QUICPacketHandler.cc
@@ -37,14 +37,17 @@
#include "QUICMultiCertConfigLoader.h"
#include "QUICTLS.h"
-static constexpr char debug_tag[] = "quic_sec";
+static constexpr char debug_tag[] = "quic_sec";
+static constexpr char v_debug_tag[] = "v_quic_sec";
#define QUICDebug(fmt, ...) Debug(debug_tag, fmt, ##__VA_ARGS__)
-#define QUICDebugQC(qc, fmt, ...) Debug(debug_tag, "[%s] " fmt, qc->cids().data(), ##__VA_ARGS__)
+#define QUICQCDebug(qc, fmt, ...) Debug(debug_tag, "[%s] " fmt, qc->cids().data(), ##__VA_ARGS__)
// ["local dcid" - "local scid"]
-#define QUICDebugDS(dcid, scid, fmt, ...) \
+#define QUICPHDebug(dcid, scid, fmt, ...) \
Debug(debug_tag, "[%08" PRIx32 "-%08" PRIx32 "] " fmt, dcid.h32(), scid.h32(), ##__VA_ARGS__)
+#define QUICVPHDebug(dcid, scid, fmt, ...) \
+ Debug(v_debug_tag, "[%08" PRIx32 "-%08" PRIx32 "] " fmt, dcid.h32(), scid.h32(), ##__VA_ARGS__)
//
// QUICPacketHandler
@@ -99,7 +102,7 @@ QUICPacketHandler::_send_packet(UDPConnection *udp_con, IpEndpoint &addr, Ptr<IO
{
UDPPacket *udp_packet = new_UDPPacket(addr, 0, udp_payload);
- if (is_debug_tag_set(debug_tag)) {
+ if (is_debug_tag_set(v_debug_tag)) {
ip_port_text_buffer ipb;
QUICConnectionId dcid = QUICConnectionId::ZERO();
QUICConnectionId scid = QUICConnectionId::ZERO();
@@ -117,8 +120,8 @@ QUICPacketHandler::_send_packet(UDPConnection *udp_con, IpEndpoint &addr, Ptr<IO
}
}
- QUICDebugDS(dcid, scid, "send %s packet to %s from port %u size=%" PRId64, (QUICInvariants::is_long_header(buf) ? "LH" : "SH"),
- ats_ip_nptop(&addr, ipb, sizeof(ipb)), udp_con->getPortNum(), buf_len);
+ QUICVPHDebug(dcid, scid, "send %s packet to %s from port %u size=%" PRId64, (QUICInvariants::is_long_header(buf) ? "LH" : "SH"),
+ ats_ip_nptop(&addr, ipb, sizeof(ipb)), udp_con->getPortNum(), buf_len);
}
udp_con->send(this->_get_continuation(), udp_packet);
@@ -215,6 +218,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet)
IOBufferBlock *block = udp_packet->getIOBlockChain();
const uint8_t *buf = reinterpret_cast<uint8_t *>(block->buf());
uint64_t buf_len = block->size();
+ QUICVersion version;
if (buf_len == 0) {
QUICDebug("Ignore packet - payload is too small");
@@ -238,25 +242,24 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet)
return;
}
- if (is_debug_tag_set(debug_tag)) {
+ if (is_debug_tag_set(v_debug_tag)) {
ip_port_text_buffer ipb_from;
ip_port_text_buffer ipb_to;
- QUICDebugDS(scid, dcid, "recv LH packet from %s to %s size=%" PRId64,
- ats_ip_nptop(&udp_packet->from.sa, ipb_from, sizeof(ipb_from)),
- ats_ip_nptop(&udp_packet->to.sa, ipb_to, sizeof(ipb_to)), udp_packet->getPktLength());
+ QUICVPHDebug(scid, dcid, "recv LH packet from %s to %s size=%" PRId64,
+ ats_ip_nptop(&udp_packet->from.sa, ipb_from, sizeof(ipb_from)),
+ ats_ip_nptop(&udp_packet->to.sa, ipb_to, sizeof(ipb_to)), udp_packet->getPktLength());
}
- QUICVersion v;
- if (unlikely(!QUICInvariants::version(v, buf, buf_len))) {
+ if (unlikely(!QUICInvariants::version(version, buf, buf_len))) {
QUICDebug("Ignore packet - payload is too small");
udp_packet->free();
return;
}
- if (!QUICInvariants::is_version_negotiation(v) && !QUICTypeUtil::is_supported_version(v)) {
- QUICDebugDS(scid, dcid, "Unsupported version: 0x%x", v);
+ if (!QUICInvariants::is_version_negotiation(version) && !QUICTypeUtil::is_supported_version(version)) {
+ QUICPHDebug(scid, dcid, "Unsupported version: 0x%x", version);
- QUICPacketUPtr vn = QUICPacketFactory::create_version_negotiation_packet(scid, dcid);
+ QUICPacketUPtr vn = QUICPacketFactory::create_version_negotiation_packet(scid, dcid, version);
this->_send_packet(*vn, udp_packet->getConnection(), udp_packet->from, 1200, nullptr, 0);
udp_packet->free();
return;
@@ -281,12 +284,12 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet)
}
} else {
// TODO: lookup DCID by 5-tuple when ATS omits SCID
- if (is_debug_tag_set(debug_tag)) {
+ if (is_debug_tag_set(v_debug_tag)) {
ip_port_text_buffer ipb_from;
ip_port_text_buffer ipb_to;
- QUICDebugDS(scid, dcid, "recv SH packet from %s to %s size=%" PRId64,
- ats_ip_nptop(&udp_packet->from.sa, ipb_from, sizeof(ipb_from)),
- ats_ip_nptop(&udp_packet->to.sa, ipb_to, sizeof(ipb_to)), udp_packet->getPktLength());
+ QUICVPHDebug(scid, dcid, "recv SH packet from %s to %s size=%" PRId64,
+ ats_ip_nptop(&udp_packet->from.sa, ipb_from, sizeof(ipb_from)),
+ ats_ip_nptop(&udp_packet->to.sa, ipb_to, sizeof(ipb_to)), udp_packet->getPktLength());
}
}
@@ -295,9 +298,11 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet)
// Server Stateless Retry
QUICConfig::scoped_config params;
- QUICConnectionId cid_in_retry_token = QUICConnectionId::ZERO();
+ QUICConnectionId ocid_in_retry_token = QUICConnectionId::ZERO();
+ QUICConnectionId rcid_in_retry_token = QUICConnectionId::ZERO();
if (!vc && params->stateless_retry() && QUICInvariants::is_long_header(buf)) {
- int ret = this->_stateless_retry(buf, buf_len, udp_packet->getConnection(), udp_packet->from, dcid, scid, &cid_in_retry_token);
+ int ret = this->_stateless_retry(buf, buf_len, udp_packet->getConnection(), udp_packet->from, dcid, scid, &ocid_in_retry_token,
+ &rcid_in_retry_token, version);
if (ret < 0) {
udp_packet->free();
return;
@@ -320,7 +325,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet)
udp_packet->free();
if (is_debug_tag_set(debug_tag) && sent) {
- QUICDebugDS(scid, dcid, "sent Stateless Reset : connection not found, dcid=%s", dcid.hex().c_str());
+ QUICPHDebug(scid, dcid, "sent Stateless Reset : connection not found, dcid=%s", dcid.hex().c_str());
}
return;
@@ -331,7 +336,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet)
udp_packet->free();
if (is_debug_tag_set(debug_tag) && sent) {
- QUICDebugDS(scid, dcid, "sent Stateless Reset : connection is already closed, dcid=%s", dcid.hex().c_str());
+ QUICPHDebug(scid, dcid, "sent Stateless Reset : connection is already closed, dcid=%s", dcid.hex().c_str());
}
return;
@@ -348,11 +353,12 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet)
QUICConnectionId peer_cid = scid;
if (is_debug_tag_set("quic_sec")) {
- QUICDebugDS(peer_cid, original_cid, "client initial dcid=%s", original_cid.hex().c_str());
+ QUICPHDebug(peer_cid, original_cid, "client initial dcid=%s", original_cid.hex().c_str());
}
vc = static_cast<QUICNetVConnection *>(getNetProcessor()->allocate_vc(nullptr));
- vc->init(peer_cid, original_cid, cid_in_retry_token, udp_packet->getConnection(), this, &this->_rtable, &this->_ctable);
+ vc->init(version, peer_cid, original_cid, ocid_in_retry_token, rcid_in_retry_token, udp_packet->getConnection(), this,
+ &this->_rtable, &this->_ctable);
vc->id = net_next_connection_number();
vc->con.move(con);
vc->submit_time = Thread::get_hrtime();
@@ -393,7 +399,8 @@ QUICPacketHandler::send_packet(QUICNetVConnection *vc, const Ptr<IOBufferBlock>
int
QUICPacketHandlerIn::_stateless_retry(const uint8_t *buf, uint64_t buf_len, UDPConnection *connection, IpEndpoint from,
- QUICConnectionId dcid, QUICConnectionId scid, QUICConnectionId *original_cid)
+ QUICConnectionId dcid, QUICConnectionId scid, QUICConnectionId *original_cid,
+ QUICConnectionId *retry_cid, QUICVersion version)
{
QUICPacketType type = QUICPacketType::UNINITIALIZED;
QUICPacketR::type(type, buf, buf_len);
@@ -411,14 +418,14 @@ QUICPacketHandlerIn::_stateless_retry(const uint8_t *buf, uint64_t buf_len, UDPC
}
if (token_length == 0) {
- QUICRetryToken token(from, dcid);
QUICConnectionId local_cid;
local_cid.randomize();
- QUICPacketUPtr retry_packet = QUICPacketFactory::create_retry_packet(scid, local_cid, token);
+ QUICRetryToken token(from, dcid, local_cid);
+ QUICPacketUPtr retry_packet = QUICPacketFactory::create_retry_packet(version, scid, local_cid, token);
- QUICDebug("[TX] %s packet ODCID=%" PRIx64 " token_length=%u token=%02x%02x%02x%02x...",
- QUICDebugNames::packet_type(retry_packet->type()), static_cast<uint64_t>(token.original_dcid()), token.length(),
- token.buf()[0], token.buf()[1], token.buf()[2], token.buf()[3]);
+ QUICDebug("[TX] %s packet ODCID=%" PRIx64 " RCID=%" PRIx64 " token_length=%u token=%02x%02x%02x%02x...",
+ QUICDebugNames::packet_type(retry_packet->type()), static_cast<uint64_t>(token.original_dcid()),
+ static_cast<uint64_t>(token.scid()), token.length(), token.buf()[0], token.buf()[1], token.buf()[2], token.buf()[3]);
this->_send_packet(*retry_packet, connection, from, 1200, nullptr, 0);
return -2;
@@ -429,12 +436,14 @@ QUICPacketHandlerIn::_stateless_retry(const uint8_t *buf, uint64_t buf_len, UDPC
QUICRetryToken token(buf + token_offset, token_length);
if (token.is_valid(from)) {
*original_cid = token.original_dcid();
- QUICDebug("Retry Token is valid. ODCID=%" PRIx64, static_cast<uint64_t>(*original_cid));
+ *retry_cid = token.scid();
+ QUICDebug("Retry Token is valid. ODCID=%" PRIx64 " RCID=%" PRIx64, static_cast<uint64_t>(*original_cid),
+ static_cast<uint64_t>(*retry_cid));
return 0;
} else {
- QUICDebug("Retry token is invalid: ODCID=%" PRIx64 "token_length=%u token=%02x%02x%02x%02x...",
- static_cast<uint64_t>(token.original_dcid()), token.length(), token.buf()[0], token.buf()[1], token.buf()[2],
- token.buf()[3]);
+ QUICDebug("Retry token is invalid: ODCID=%" PRIx64 " RCID=%" PRIx64 " token_length=%u token=%02x%02x%02x%02x...",
+ static_cast<uint64_t>(token.original_dcid()), static_cast<uint64_t>(*retry_cid), token.length(), token.buf()[0],
+ token.buf()[1], token.buf()[2], token.buf()[3]);
this->_send_invalid_token_error(buf, buf_len, connection, from);
return -3;
}
@@ -468,6 +477,8 @@ QUICPacketHandlerIn::_send_invalid_token_error(const uint8_t *initial_packet, ui
QUICConnectionId dcid_in_initial;
QUICInvariants::scid(scid_in_initial, initial_packet, initial_packet_len);
QUICInvariants::dcid(dcid_in_initial, initial_packet, initial_packet_len);
+ QUICVersion version_in_initial;
+ QUICLongHeaderPacketR::version(version_in_initial, initial_packet, initial_packet_len);
// Create CONNECTION_CLOSE frame
auto error = std::make_unique<QUICConnectionError>(QUICTransErrorCode::INVALID_TOKEN);
@@ -487,7 +498,7 @@ QUICPacketHandlerIn::_send_invalid_token_error(const uint8_t *initial_packet, ui
QUICPacketHeaderProtector php(ppki);
QUICCertConfig::scoped_config server_cert;
QUICTLS tls(ppki, server_cert->ssl_default.get(), NET_VCONNECTION_IN, {}, "", "");
- tls.initialize_key_materials(dcid_in_initial);
+ tls.initialize_key_materials(dcid_in_initial, version_in_initial);
// Create INITIAL packet
QUICConnectionId scid;
@@ -553,7 +564,7 @@ QUICPacketHandlerOut::_recv_packet(int event, UDPPacket *udp_packet)
if (is_debug_tag_set(debug_tag)) {
ip_port_text_buffer ipb_from;
ip_port_text_buffer ipb_to;
- QUICDebugQC(this->_vc, "recv %s packet from %s to %s size=%" PRId64, (QUICInvariants::is_long_header(buf) ? "LH" : "SH"),
+ QUICQCDebug(this->_vc, "recv %s packet from %s to %s size=%" PRId64, (QUICInvariants::is_long_header(buf) ? "LH" : "SH"),
ats_ip_nptop(&udp_packet->from.sa, ipb_from, sizeof(ipb_from)),
ats_ip_nptop(&udp_packet->to.sa, ipb_to, sizeof(ipb_to)), udp_packet->getPktLength());
}
diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am
index 75c4daf..fc02e6d 100644
--- a/iocore/net/quic/Makefile.am
+++ b/iocore/net/quic/Makefile.am
@@ -142,7 +142,7 @@ TESTS = $(check_PROGRAMS)
test_CPPFLAGS = \
$(AM_CPPFLAGS) \
- -I$(abs_top_srcdir)/tests/include
+ -I$(abs_top_srcdir)/tests/include -O0
test_LDADD = \
libquic.a \
diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h
index 68e421a..c0d28a3 100644
--- a/iocore/net/quic/Mock.h
+++ b/iocore/net/quic/Mock.h
@@ -28,6 +28,9 @@
#include "QUICApplication.h"
#include "QUICStreamManager.h"
#include "QUICLossDetector.h"
+#include "QUICPacketProtectionKeyInfo.h"
+#include "QUICPinger.h"
+#include "QUICPadder.h"
#include "QUICEvents.h"
#include "QUICPacketProtectionKeyInfo.h"
#include "QUICPinger.h"
@@ -37,7 +40,7 @@
class MockQUICContext;
using namespace std::literals;
-std::string_view negotiated_application_name_sv = "h3-27"sv;
+std::string_view negotiated_application_name_sv = "h3-29"sv;
class MockQUICLDConfig : public QUICLDConfig
{
@@ -154,6 +157,18 @@ class MockQUICConnectionInfoProvider : public QUICConnectionInfoProvider
return {reinterpret_cast<const uint8_t *>("\x00"), 1};
}
+ QUICConnectionId
+ retry_source_connection_id() const override
+ {
+ return {reinterpret_cast<const uint8_t *>("\x00"), 1};
+ }
+
+ QUICConnectionId
+ initial_source_connection_id() const override
+ {
+ return {reinterpret_cast<const uint8_t *>("\x00"), 1};
+ }
+
const QUICFiveTuple
five_tuple() const override
{
@@ -192,6 +207,36 @@ class MockQUICConnectionInfoProvider : public QUICConnectionInfoProvider
return false;
}
+ bool
+ is_at_anti_amplification_limit() const override
+ {
+ return false;
+ }
+
+ bool
+ is_address_validation_completed() const override
+ {
+ return true;
+ }
+
+ bool
+ is_handshake_completed() const override
+ {
+ return true;
+ }
+
+ bool
+ has_keys_for(QUICPacketNumberSpace space) const override
+ {
+ return true;
+ }
+
+ QUICVersion
+ negotiated_version() const override
+ {
+ return QUIC_SUPPORTED_VERSIONS[0];
+ }
+
std::string_view
negotiated_application_name() const override
{
@@ -341,6 +386,18 @@ public:
return {reinterpret_cast<const uint8_t *>("\x00"), 1};
}
+ QUICConnectionId
+ retry_source_connection_id() const override
+ {
+ return {reinterpret_cast<const uint8_t *>("\x00"), 1};
+ }
+
+ QUICConnectionId
+ initial_source_connection_id() const override
+ {
+ return {reinterpret_cast<const uint8_t *>("\x00"), 1};
+ }
+
const QUICFiveTuple
five_tuple() const override
{
@@ -409,6 +466,30 @@ public:
return false;
}
+ bool
+ is_at_anti_amplification_limit() const override
+ {
+ return false;
+ }
+
+ bool
+ is_address_validation_completed() const override
+ {
+ return true;
+ }
+
+ bool
+ is_handshake_completed() const override
+ {
+ return true;
+ }
+
+ bool
+ has_keys_for(QUICPacketNumberSpace space) const override
+ {
+ return true;
+ }
+
void
handle_received_packet(UDPPacket *) override
{
@@ -419,6 +500,12 @@ public:
{
}
+ QUICVersion
+ negotiated_version() const override
+ {
+ return QUIC_SUPPORTED_VERSIONS[0];
+ }
+
std::string_view
negotiated_application_name() const override
{
@@ -448,7 +535,7 @@ public:
MockQUICCongestionController() {}
// Override
virtual void
- on_packets_lost(const std::map<QUICPacketNumber, QUICPacketInfo *> &packets) override
+ on_packets_lost(const std::map<QUICPacketNumber, QUICSentPacketInfoUPtr> &packets) override
{
for (auto &p : packets) {
lost_packets.insert(p.first);
@@ -460,11 +547,15 @@ public:
{
}
virtual void
- on_packet_acked(const QUICPacketInfo &acked_packet) override
+ on_packets_acked(const std::vector<QUICSentPacketInfoUPtr> &packets) override
+ {
+ }
+ void
+ on_packet_number_space_discarded(size_t bytes_in_flight) override
{
}
virtual void
- process_ecn(const QUICPacketInfo &acked_largest_packet, const QUICAckFrame::EcnSection *ecn_section) override
+ process_ecn(const QUICAckFrame &ack_frame, QUICPacketNumberSpace pn_space, ink_hrtime largest_acked_time_sent) override
{
}
virtual void
@@ -627,6 +718,12 @@ public:
{
}
+ void
+ on_packet_number_space_discarded(QUICPacketNumberSpace pn_space)
+ {
+ this->_cc.on_packet_number_space_discarded(0);
+ }
+
private:
QUICPinger _pinger;
QUICPadder _padder;
@@ -740,7 +837,7 @@ public:
}
int
- initialize_key_materials(QUICConnectionId cid) override
+ initialize_key_materials(QUICConnectionId cid, QUICVersion version) override
{
return 0;
}
diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc
index dd2e2f9..bee2b76 100644
--- a/iocore/net/quic/QUICAckFrameCreator.cc
+++ b/iocore/net/quic/QUICAckFrameCreator.cc
@@ -28,7 +28,7 @@
QUICAckFrameManager::QUICAckFrameManager()
{
- for (auto i = 0; i < kPacketNumberSpace; i++) {
+ for (auto i = 0; i < QUIC_N_PACKET_SPACES; i++) {
this->_ack_creator[i] = std::make_unique<QUICAckFrameCreator>(static_cast<QUICPacketNumberSpace>(i), this);
}
}
@@ -132,7 +132,7 @@ QUICAckFrameManager::ack_delay_exponent() const
void
QUICAckFrameManager::set_max_ack_delay(uint16_t delay)
{
- for (auto i = 0; i < kPacketNumberSpace; i++) {
+ for (auto i = 0; i < QUIC_N_PACKET_SPACES; i++) {
this->_ack_creator[i]->set_max_ack_delay(delay);
}
}
@@ -193,7 +193,7 @@ QUICAckFrameManager::QUICAckFrameCreator::push_back(QUICPacketNumber packet_numb
}
// can not delay handshake packet
- if ((this->_pn_space == QUICPacketNumberSpace::Initial || this->_pn_space == QUICPacketNumberSpace::Handshake) && !ack_only) {
+ if ((this->_pn_space == QUICPacketNumberSpace::INITIAL || this->_pn_space == QUICPacketNumberSpace::HANDSHAKE) && !ack_only) {
this->_should_send = true;
}
@@ -335,7 +335,7 @@ QUICAckFrameManager::QUICAckFrameCreator::_calculate_delay()
ink_hrtime now = Thread::get_hrtime();
uint64_t delay = (now - this->_largest_ack_received_time) / 1000;
uint8_t ack_delay_exponent = 3;
- if (this->_pn_space != QUICPacketNumberSpace::Initial && this->_pn_space != QUICPacketNumberSpace::Handshake) {
+ if (this->_pn_space != QUICPacketNumberSpace::INITIAL && this->_pn_space != QUICPacketNumberSpace::HANDSHAKE) {
ack_delay_exponent = this->_ack_manager->ack_delay_exponent();
}
return delay >> ack_delay_exponent;
diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h
index 4fc89ba..55e20f2 100644
--- a/iocore/net/quic/QUICAckFrameCreator.h
+++ b/iocore/net/quic/QUICAckFrameCreator.h
@@ -78,7 +78,7 @@ public:
QUICAckFrameManager *_ack_manager = nullptr;
- QUICPacketNumberSpace _pn_space = QUICPacketNumberSpace::Initial;
+ QUICPacketNumberSpace _pn_space = QUICPacketNumberSpace::INITIAL;
};
static constexpr int MAXIMUM_PACKET_COUNT = 256;
diff --git a/iocore/net/quic/QUICAddrVerifyState.cc b/iocore/net/quic/QUICAddrVerifyState.cc
index 67281b5..6db5019 100644
--- a/iocore/net/quic/QUICAddrVerifyState.cc
+++ b/iocore/net/quic/QUICAddrVerifyState.cc
@@ -48,7 +48,7 @@ QUICAddrVerifyState::consume(uint32_t windows)
}
uint32_t
-QUICAddrVerifyState::windows()
+QUICAddrVerifyState::windows() const
{
return this->_windows;
}
diff --git a/iocore/net/quic/QUICAddrVerifyState.h b/iocore/net/quic/QUICAddrVerifyState.h
index d6d6c7c..6b454e4 100644
--- a/iocore/net/quic/QUICAddrVerifyState.h
+++ b/iocore/net/quic/QUICAddrVerifyState.h
@@ -34,7 +34,7 @@ public:
void fill(uint32_t windows);
void consume(uint32_t windows);
void set_addr_verifed();
- uint32_t windows();
+ uint32_t windows() const;
bool is_verified() const;
private:
diff --git a/iocore/net/quic/QUICBidirectionalStream.cc b/iocore/net/quic/QUICBidirectionalStream.cc
index 9565b0a..a5d2f71 100644
--- a/iocore/net/quic/QUICBidirectionalStream.cc
+++ b/iocore/net/quic/QUICBidirectionalStream.cc
@@ -469,8 +469,8 @@ QUICBidirectionalStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level,
// Calling update always success, because len is always less than stream_credit
ink_assert(ret == 0);
- QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(),
- this->_remote_flow_controller.current_limit());
+ QUICVStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(),
+ this->_remote_flow_controller.current_limit());
if (this->_remote_flow_controller.current_offset() == this->_remote_flow_controller.current_limit()) {
QUICStreamDebug("Flow Controller will block sending a STREAM frame");
}
diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc
index 8e39794..aec4f13 100644
--- a/iocore/net/quic/QUICConfig.cc
+++ b/iocore/net/quic/QUICConfig.cc
@@ -179,9 +179,8 @@ QUICConfigParams::initialize()
this->_ld_initial_rtt = HRTIME_MSECONDS(timeout);
// Congestion Control
- REC_EstablishStaticConfigInt32U(this->_cc_max_datagram_size, "proxy.config.quic.congestion_control.max_datagram_size");
- REC_EstablishStaticConfigInt32U(this->_cc_initial_window_scale, "proxy.config.quic.congestion_control.initial_window_scale");
- REC_EstablishStaticConfigInt32U(this->_cc_minimum_window_scale, "proxy.config.quic.congestion_control.minimum_window_scale");
+ REC_EstablishStaticConfigInt32U(this->_cc_initial_window, "proxy.config.quic.congestion_control.initial_window");
+ REC_EstablishStaticConfigInt32U(this->_cc_minimum_window, "proxy.config.quic.congestion_control.minimum_window");
REC_EstablishStaticConfigFloat(this->_cc_loss_reduction_factor, "proxy.config.quic.congestion_control.loss_reduction_factor");
REC_EstablishStaticConfigInt32U(this->_cc_persistent_congestion_threshold,
"proxy.config.quic.congestion_control.persistent_congestion_threshold");
@@ -420,26 +419,15 @@ QUICConfigParams::ld_initial_rtt() const
}
uint32_t
-QUICConfigParams::cc_max_datagram_size() const
-{
- return _cc_max_datagram_size;
-}
-
-uint32_t
QUICConfigParams::cc_initial_window() const
{
- // kInitialWindow: Default limit on the initial amount of data in
- // flight, in bytes. Taken from [RFC6928]. The RECOMMENDED value is
- // the minimum of 10 * kMaxDatagramSize and max(2* kMaxDatagramSize,
- // 14600)).
- return std::min(_cc_initial_window_scale * _cc_max_datagram_size,
- std::max(2 * _cc_max_datagram_size, static_cast<uint32_t>(14600)));
+ return _cc_initial_window;
}
uint32_t
QUICConfigParams::cc_minimum_window() const
{
- return _cc_minimum_window_scale * _cc_max_datagram_size;
+ return _cc_minimum_window;
}
float
diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h
index 38a655a..0ce045a 100644
--- a/iocore/net/quic/QUICConfig.h
+++ b/iocore/net/quic/QUICConfig.h
@@ -146,9 +146,8 @@ private:
ink_hrtime _ld_initial_rtt = HRTIME_MSECONDS(500);
// [draft-11 recovery] 4.7.1. Constants of interest
- uint32_t _cc_max_datagram_size = 1200;
- uint32_t _cc_initial_window_scale = 10; // Actual initial window size is this value multiplied by the _cc_default_mss
- uint32_t _cc_minimum_window_scale = 2; // Actual minimum window size is this value multiplied by the _cc_default_mss
+ uint32_t _cc_initial_window = 1200 * 10;
+ uint32_t _cc_minimum_window = 1200 * 2;
float _cc_loss_reduction_factor = 0.5;
uint32_t _cc_persistent_congestion_threshold = 3;
};
diff --git a/iocore/net/quic/QUICCongestionController.h b/iocore/net/quic/QUICCongestionController.h
index 42b4a8b..7417ac8 100644
--- a/iocore/net/quic/QUICCongestionController.h
+++ b/iocore/net/quic/QUICCongestionController.h
@@ -25,22 +25,6 @@
#include "QUICFrame.h"
-struct QUICPacketInfo {
- // 6.3.1. Sent Packet Fields
- QUICPacketNumber packet_number;
- ink_hrtime time_sent;
- bool ack_eliciting;
- bool is_crypto_packet;
- bool in_flight;
- size_t sent_bytes;
-
- // addition
- QUICPacketType type;
- std::vector<QUICFrameInfo> frames;
- QUICPacketNumberSpace pn_space;
- // end
-};
-
class QUICCongestionController
{
public:
@@ -52,15 +36,21 @@ public:
};
virtual ~QUICCongestionController() {}
- virtual void on_packet_sent(size_t bytes_sent) = 0;
- virtual void on_packet_acked(const QUICPacketInfo &acked_packet) = 0;
- virtual void process_ecn(const QUICPacketInfo &acked_largest_packet, const QUICAckFrame::EcnSection *ecn_section) = 0;
- virtual void on_packets_lost(const std::map<QUICPacketNumber, QUICPacketInfo *> &packets) = 0;
- virtual void add_extra_credit() = 0;
- virtual void reset() = 0;
- virtual uint32_t credit() const = 0;
+ // Appendix B. Congestion Control Pseudocode
+ virtual void on_packet_sent(size_t bytes_sent) = 0;
+ virtual void on_packets_acked(const std::vector<QUICSentPacketInfoUPtr> &packets) = 0;
+ virtual void process_ecn(const QUICAckFrame &ack, QUICPacketNumberSpace pn_space, ink_hrtime largest_acked_packet_time_sent) = 0;
+ virtual void on_packets_lost(const std::map<QUICPacketNumber, QUICSentPacketInfoUPtr> &packets) = 0;
+ // The function signature is different from the pseudo code because LD takes care of most of the processes
+ virtual void on_packet_number_space_discarded(size_t bytes_in_flight) = 0;
+
+ // These are additional and not on the spec
+ virtual void add_extra_credit() = 0;
+ virtual void reset() = 0;
+ virtual uint32_t credit() const = 0;
+ virtual uint32_t bytes_in_flight() const = 0;
+
// Debug
- virtual uint32_t bytes_in_flight() const = 0;
virtual uint32_t congestion_window() const = 0;
virtual uint32_t current_ssthresh() const = 0;
};
diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h
index 57d64ba..02cbbb0 100644
--- a/iocore/net/quic/QUICConnection.h
+++ b/iocore/net/quic/QUICConnection.h
@@ -37,16 +37,32 @@ public:
virtual ~QUICConnectionInfoProvider() {}
virtual QUICConnectionId peer_connection_id() const = 0;
virtual QUICConnectionId original_connection_id() const = 0;
- virtual QUICConnectionId first_connection_id() const = 0;
- virtual QUICConnectionId connection_id() const = 0;
- virtual std::string_view cids() const = 0;
- virtual const QUICFiveTuple five_tuple() const = 0;
+ /**
+ * This is S1 on 7.3.Authenticating Connection IDs
+ */
+ virtual QUICConnectionId first_connection_id() const = 0;
+ /**
+ * This is S2 on 7.3.Authenticating Connection IDs
+ */
+ virtual QUICConnectionId retry_source_connection_id() const = 0;
+ /**
+ * This is C1 or S3 on 7.3.Authenticating Connection IDs
+ */
+ virtual QUICConnectionId initial_source_connection_id() const = 0;
+ virtual QUICConnectionId connection_id() const = 0;
+ virtual std::string_view cids() const = 0;
+ virtual const QUICFiveTuple five_tuple() const = 0;
virtual uint32_t pmtu() const = 0;
virtual NetVConnectionContext_t direction() const = 0;
virtual int select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in,
unsigned inlen) const = 0;
virtual bool is_closed() const = 0;
+ virtual bool is_at_anti_amplification_limit() const = 0;
+ virtual bool is_address_validation_completed() const = 0;
+ virtual bool is_handshake_completed() const = 0;
+ virtual bool has_keys_for(QUICPacketNumberSpace space) const = 0;
+ virtual QUICVersion negotiated_version() const = 0;
virtual std::string_view negotiated_application_name() const = 0;
};
diff --git a/iocore/net/quic/QUICContext.cc b/iocore/net/quic/QUICContext.cc
index 4d0d501..b065f56 100644
--- a/iocore/net/quic/QUICContext.cc
+++ b/iocore/net/quic/QUICContext.cc
@@ -33,12 +33,6 @@ public:
QUICCCConfigQCP(const QUICConfigParams *params) : _params(params) {}
uint32_t
- max_datagram_size() const override
- {
- return this->_params->cc_max_datagram_size();
- }
-
- uint32_t
initial_window() const override
{
return this->_params->cc_initial_window();
@@ -151,4 +145,4 @@ QUICPathManager *
QUICContext::path_manager() const
{
return _path_manager;
-}
\ No newline at end of file
+}
diff --git a/iocore/net/quic/QUICContext.h b/iocore/net/quic/QUICContext.h
index 13f8935..ab2dae9 100644
--- a/iocore/net/quic/QUICContext.h
+++ b/iocore/net/quic/QUICContext.h
@@ -23,6 +23,7 @@
#pragma once
+#include "QUICTypes.h"
#include "QUICConnection.h"
#include "QUICConfig.h"
#include "QUICEvents.h"
@@ -54,7 +55,7 @@ public:
// callback on packet send event
virtual void packet_send_callback(QUICCallbackContext &, const QUICPacket &p){};
// callback on packet lost event
- virtual void packet_lost_callback(QUICCallbackContext &, const QUICPacketInfo &p){};
+ virtual void packet_lost_callback(QUICCallbackContext &, const QUICSentPacketInfo &p){};
// callback on packet receive event
virtual void packet_recv_callback(QUICCallbackContext &, const QUICPacket &p){};
// callback on packet acked event
@@ -128,7 +129,7 @@ public:
}
void
- trigger(CallbackEvent e, const QUICPacketInfo &p)
+ trigger(CallbackEvent e, const QUICSentPacketInfo &p)
{
QUICCallbackContext ctx;
for (auto &&it : this->_callbacks) {
diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc
index 6a75032..79d2797 100644
--- a/iocore/net/quic/QUICDebugNames.cc
+++ b/iocore/net/quic/QUICDebugNames.cc
@@ -121,6 +121,8 @@ QUICDebugNames::error_code(uint16_t code)
return "NO_ERROR";
case static_cast<uint16_t>(QUICTransErrorCode::INTERNAL_ERROR):
return "INTERNAL_ERROR";
+ case static_cast<uint16_t>(QUICTransErrorCode::CONNECTION_REFUSED):
+ return "CONNECTION_REFUSED";
case static_cast<uint16_t>(QUICTransErrorCode::FLOW_CONTROL_ERROR):
return "FLOW_CONTROL_ERROR";
case static_cast<uint16_t>(QUICTransErrorCode::STREAM_LIMIT_ERROR):
@@ -139,6 +141,8 @@ QUICDebugNames::error_code(uint16_t code)
return "PROTOCOL_VIOLATION";
case static_cast<uint16_t>(QUICTransErrorCode::INVALID_TOKEN):
return "INVALID_TOKEN";
+ case static_cast<uint16_t>(QUICTransErrorCode::APPLICATION_ERROR):
+ return "APPLICATION_ERROR";
case static_cast<uint16_t>(QUICTransErrorCode::CRYPTO_BUFFER_EXCEEDED):
return "CRYPTO_BUFFER_EXCEEDED";
default:
@@ -189,8 +193,8 @@ QUICDebugNames::transport_parameter_id(QUICTransportParameterId id)
return "MAX_IDLE_TIMEOUT";
case QUICTransportParameterId::PREFERRED_ADDRESS:
return "PREFERRED_ADDRESS";
- case QUICTransportParameterId::MAX_PACKET_SIZE:
- return "MAX_PACKET_SIZE";
+ case QUICTransportParameterId::MAX_UDP_PAYLOAD_SIZE:
+ return "MAX_UDP_PAYLOAD_SIZE";
case QUICTransportParameterId::STATELESS_RESET_TOKEN:
return "STATELESS_RESET_TOKEN";
case QUICTransportParameterId::ACK_DELAY_EXPONENT:
@@ -205,10 +209,14 @@ QUICDebugNames::transport_parameter_id(QUICTransportParameterId id)
return "INITIAL_MAX_STREAM_DATA_UNI";
case QUICTransportParameterId::MAX_ACK_DELAY:
return "INITIAL_MAX_ACK_DELAY";
- case QUICTransportParameterId::ORIGINAL_CONNECTION_ID:
- return "INITIAL_ORIGINAL_CONNECTION_ID";
+ case QUICTransportParameterId::ORIGINAL_DESTINATION_CONNECTION_ID:
+ return "INITIAL_ORIGINAL_DESTINATION_CONNECTION_ID";
case QUICTransportParameterId::ACTIVE_CONNECTION_ID_LIMIT:
return "ACTIVE_CONNECTION_ID_LIMIT";
+ case QUICTransportParameterId::INITIAL_SOURCE_CONNECTION_ID:
+ return "INITIAL_SOURCE_CONNECTION_ID";
+ case QUICTransportParameterId::RETRY_SOURCE_CONNECTION_ID:
+ return "RETRY_SOURCE_CONNECTION_ID";
default:
return "UNKNOWN";
}
@@ -323,12 +331,12 @@ const char *
QUICDebugNames::pn_space(QUICPacketNumberSpace pn_space)
{
switch (pn_space) {
- case QUICPacketNumberSpace::Initial:
- return "QUICPacketNumberSpace::Initial";
- case QUICPacketNumberSpace::Handshake:
- return "QUICPacketNumberSpace::Handshake";
- case QUICPacketNumberSpace::ApplicationData:
- return "QUICPacketNumberSpace::ApplicationData";
+ case QUICPacketNumberSpace::INITIAL:
+ return "INITIAL";
+ case QUICPacketNumberSpace::HANDSHAKE:
+ return "HANDSHAKE";
+ case QUICPacketNumberSpace::APPLICATION_DATA:
+ return "APPLCIATION_DATA";
default:
return "UNKNOWN";
}
diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc
index 7af9a7a..35c14b6 100644
--- a/iocore/net/quic/QUICFrame.cc
+++ b/iocore/net/quic/QUICFrame.cc
@@ -3104,15 +3104,3 @@ QUICFrameFactory::create_handshake_done_frame(uint8_t *buf, QUICFrameId id, QUIC
new (buf) QUICHandshakeDoneFrame(id, owner);
return reinterpret_cast<QUICHandshakeDoneFrame *>(buf);
}
-
-QUICFrameId
-QUICFrameInfo::id() const
-{
- return this->_id;
-}
-
-QUICFrameGenerator *
-QUICFrameInfo::generated_by() const
-{
- return this->_generator;
-}
diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h
index 14b87d3..93cd692 100644
--- a/iocore/net/quic/QUICFrame.h
+++ b/iocore/net/quic/QUICFrame.h
@@ -40,8 +40,6 @@ class QUICCryptoFrame;
class QUICPacketR;
class QUICFrameGenerator;
-using QUICFrameId = uint64_t;
-
class QUICFrame
{
public:
@@ -908,15 +906,3 @@ private:
uint8_t _buf_for_fast_create[256 * QUICFrame::MAX_INSTANCE_SIZE];
QUICUnknownFrame _unknown_frame;
};
-
-class QUICFrameInfo
-{
-public:
- QUICFrameInfo(QUICFrameId id, QUICFrameGenerator *generator) : _id(id), _generator(generator) {}
- QUICFrameId id() const;
- QUICFrameGenerator *generated_by() const;
-
-private:
- QUICFrameId _id = 0;
- QUICFrameGenerator *_generator;
-};
diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc
index 9509933..131bc40 100644
--- a/iocore/net/quic/QUICFrameDispatcher.cc
+++ b/iocore/net/quic/QUICFrameDispatcher.cc
@@ -24,9 +24,11 @@
#include "QUICFrameDispatcher.h"
#include "QUICDebugNames.h"
-static constexpr char tag[] = "quic_net";
+static constexpr char tag[] = "quic_net";
+static constexpr char v_tag[] = "v_quic_net";
#define QUICDebug(fmt, ...) Debug(tag, "[%s] " fmt, this->_info->cids().data(), ##__VA_ARGS__)
+#define QUICVDebug(fmt, ...) Debug(v_tag, "[%s] " fmt, this->_info->cids().data(), ##__VA_ARGS__)
//
// Frame Dispatcher
@@ -70,10 +72,10 @@ QUICFrameDispatcher::receive_frames(QUICContext &ctx, QUICEncryptionLevel level,
is_flow_controlled = true;
}
- if (is_debug_tag_set(tag) && type != QUICFrameType::PADDING) {
+ if (is_debug_tag_set(v_tag) && type != QUICFrameType::PADDING) {
char msg[1024];
frame.debug_msg(msg, sizeof(msg));
- QUICDebug("[RX] | %s", msg);
+ QUICVDebug("[RX] | %s", msg);
}
if (type != QUICFrameType::PADDING && type != QUICFrameType::ACK) {
diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc
index c1a530f..f64f222 100644
--- a/iocore/net/quic/QUICHandshake.cc
+++ b/iocore/net/quic/QUICHandshake.cc
@@ -82,16 +82,20 @@
static constexpr int UDP_MAXIMUM_PAYLOAD_SIZE = 65527;
-QUICHandshake::QUICHandshake(QUICConnection *qc, QUICHandshakeProtocol *hsp) : QUICHandshake(qc, hsp, {}, false) {}
+QUICHandshake::QUICHandshake(QUICVersion version, QUICConnection *qc, QUICHandshakeProtocol *hsp)
+ : QUICHandshake(version, qc, hsp, {}, false)
+{
+}
-QUICHandshake::QUICHandshake(QUICConnection *qc, QUICHandshakeProtocol *hsp, QUICStatelessResetToken token, bool stateless_retry)
+QUICHandshake::QUICHandshake(QUICVersion version, QUICConnection *qc, QUICHandshakeProtocol *hsp, QUICStatelessResetToken token,
+ bool stateless_retry)
: _qc(qc),
_hs_protocol(hsp),
_version_negotiator(new QUICVersionNegotiator()),
_reset_token(token),
_stateless_retry(stateless_retry)
{
- this->_hs_protocol->initialize_key_materials(this->_qc->original_connection_id());
+ this->_hs_protocol->initialize_key_materials(this->_qc->original_connection_id(), version);
if (this->_qc->direction() == NET_VCONNECTION_OUT) {
this->_client_initial = true;
@@ -108,7 +112,7 @@ QUICHandshake::start(const QUICTPConfig &tp_config, QUICPacketFactory *packet_fa
{
QUICVersion initial_version = QUIC_SUPPORTED_VERSIONS[0];
if (vn_exercise_enabled) {
- initial_version = QUIC_EXERCISE_VERSION;
+ initial_version = QUIC_EXERCISE_VERSION1;
}
this->_load_local_client_transport_parameters(tp_config);
@@ -137,6 +141,7 @@ QUICHandshake::start(const QUICTPConfig &tp_config, const QUICInitialPacketR &in
} else {
return std::make_unique<QUICConnectionError>(QUICTransErrorCode::PROTOCOL_VIOLATION);
}
+ this->_initial_source_cid_received = initial_packet.source_cid();
}
return nullptr;
}
@@ -253,6 +258,17 @@ QUICHandshake::_check_remote_transport_parameters(std::shared_ptr<const QUICTran
return false;
}
+ // Check if CIDs in TP match with the ones in packets
+ if (this->negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]) { // draft-28
+ uint16_t cid_buf_len;
+ const uint8_t *cid_buf = tp->getAsBytes(QUICTransportParameterId::INITIAL_SOURCE_CONNECTION_ID, cid_buf_len);
+ QUICConnectionId cid_in_tp(cid_buf, cid_buf_len);
+ if (cid_in_tp != this->_initial_source_cid_received) {
+ this->_abort_handshake(QUICTransErrorCode::PROTOCOL_VIOLATION);
+ return false;
+ }
+ }
+
this->_remote_transport_parameters = tp;
return true;
@@ -268,6 +284,26 @@ QUICHandshake::_check_remote_transport_parameters(std::shared_ptr<const QUICTran
return false;
}
+ // Check if CIDs in TP match with the ones in packets
+ if (this->negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]) { // draft-28
+ uint16_t cid_buf_len;
+ const uint8_t *cid_buf = tp->getAsBytes(QUICTransportParameterId::INITIAL_SOURCE_CONNECTION_ID, cid_buf_len);
+ QUICConnectionId cid_in_tp(cid_buf, cid_buf_len);
+ if (cid_in_tp != this->_initial_source_cid_received) {
+ this->_abort_handshake(QUICTransErrorCode::PROTOCOL_VIOLATION);
+ return false;
+ }
+
+ if (!this->_retry_source_cid_received.is_zero()) {
+ cid_buf = tp->getAsBytes(QUICTransportParameterId::RETRY_SOURCE_CONNECTION_ID, cid_buf_len);
+ QUICConnectionId cid_in_tp(cid_buf, cid_buf_len);
+ if (cid_in_tp != this->_retry_source_cid_received) {
+ this->_abort_handshake(QUICTransErrorCode::PROTOCOL_VIOLATION);
+ return false;
+ }
+ }
+ }
+
this->_remote_transport_parameters = tp;
return true;
@@ -302,6 +338,18 @@ QUICHandshake::reset()
}
}
+void
+QUICHandshake::update(const QUICInitialPacketR &packet)
+{
+ this->_initial_source_cid_received = packet.source_cid();
+}
+
+void
+QUICHandshake::update(const QUICRetryPacketR &packet)
+{
+ this->_retry_source_cid_received = packet.source_cid();
+}
+
std::vector<QUICFrameType>
QUICHandshake::interests()
{
@@ -386,8 +434,19 @@ QUICHandshake::_load_local_server_transport_parameters(const QUICTPConfig &tp_co
// MUSTs
tp->set(QUICTransportParameterId::MAX_IDLE_TIMEOUT, static_cast<uint16_t>(tp_config.no_activity_timeout()));
if (this->_stateless_retry) {
- tp->set(QUICTransportParameterId::ORIGINAL_CONNECTION_ID, this->_qc->first_connection_id(),
+ tp->set(QUICTransportParameterId::ORIGINAL_DESTINATION_CONNECTION_ID, this->_qc->first_connection_id(),
this->_qc->first_connection_id().length());
+ tp->set(QUICTransportParameterId::RETRY_SOURCE_CONNECTION_ID, this->_qc->retry_source_connection_id(),
+ this->_qc->retry_source_connection_id().length());
+ } else {
+ if (this->negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]) { // draft-28
+ tp->set(QUICTransportParameterId::ORIGINAL_DESTINATION_CONNECTION_ID, this->_qc->original_connection_id(),
+ this->_qc->original_connection_id().length());
+ }
+ }
+ if (this->negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]) { // draft-28
+ tp->set(QUICTransportParameterId::INITIAL_SOURCE_CONNECTION_ID, this->_qc->initial_source_connection_id(),
+ this->_qc->initial_source_connection_id().length());
}
// MAYs
@@ -426,7 +485,10 @@ QUICHandshake::_load_local_server_transport_parameters(const QUICTPConfig &tp_co
tp->set(QUICTransportParameterId::STATELESS_RESET_TOKEN, this->_reset_token.buf(), QUICStatelessResetToken::LEN);
tp->set(QUICTransportParameterId::ACK_DELAY_EXPONENT, tp_config.ack_delay_exponent());
- tp->add_version(QUIC_SUPPORTED_VERSIONS[0]);
+ // Additional parameters
+ for (auto &¶m : tp_config.additional_tp()) {
+ tp->set(param.first, param.second.first, param.second.second);
+ }
// Additional parameters
for (auto &¶m : tp_config.additional_tp()) {
@@ -444,6 +506,8 @@ QUICHandshake::_load_local_client_transport_parameters(const QUICTPConfig &tp_co
// MUSTs
tp->set(QUICTransportParameterId::MAX_IDLE_TIMEOUT, static_cast<uint16_t>(tp_config.no_activity_timeout()));
+ tp->set(QUICTransportParameterId::INITIAL_SOURCE_CONNECTION_ID, this->_qc->initial_source_connection_id(),
+ this->_qc->initial_source_connection_id().length());
// MAYs
if (tp_config.initial_max_data() != 0) {
diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h
index 017c96d..4f55985 100644
--- a/iocore/net/quic/QUICHandshake.h
+++ b/iocore/net/quic/QUICHandshake.h
@@ -42,9 +42,10 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator
{
public:
// Constructor for client side
- QUICHandshake(QUICConnection *qc, QUICHandshakeProtocol *hsp);
+ QUICHandshake(QUICVersion version, QUICConnection *qc, QUICHandshakeProtocol *hsp);
// Constructor for server side
- QUICHandshake(QUICConnection *qc, QUICHandshakeProtocol *hsp, QUICStatelessResetToken token, bool stateless_retry);
+ QUICHandshake(QUICVersion version, QUICConnection *qc, QUICHandshakeProtocol *hsp, QUICStatelessResetToken token,
+ bool stateless_retry);
~QUICHandshake();
// QUICFrameHandler
@@ -60,6 +61,8 @@ public:
QUICConnectionErrorUPtr start(const QUICTPConfig &tp_config, QUICPacketFactory *packet_factory, bool vn_exercise_enabled);
QUICConnectionErrorUPtr negotiate_version(const QUICVersionNegotiationPacketR &packet, QUICPacketFactory *packet_factory);
void reset();
+ void update(const QUICInitialPacketR &initial_packet);
+ void update(const QUICRetryPacketR &retry_packet);
// for server side
QUICConnectionErrorUPtr start(const QUICTPConfig &tp_config, const QUICInitialPacketR &initial_packet,
@@ -91,8 +94,10 @@ private:
QUICVersionNegotiator *_version_negotiator = nullptr;
QUICStatelessResetToken _reset_token;
- bool _client_initial = false;
- bool _stateless_retry = false;
+ bool _client_initial = false;
+ bool _stateless_retry = false;
+ QUICConnectionId _initial_source_cid_received = QUICConnectionId::ZERO();
+ QUICConnectionId _retry_source_cid_received = QUICConnectionId::ZERO();
QUICCryptoStream _crypto_streams[4];
diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h
index 0c7c09b..8bc6e77 100644
--- a/iocore/net/quic/QUICHandshakeProtocol.h
+++ b/iocore/net/quic/QUICHandshakeProtocol.h
@@ -47,7 +47,7 @@ public:
virtual void reset() = 0;
virtual bool is_handshake_finished() const = 0;
virtual bool is_ready_to_derive() const = 0;
- virtual int initialize_key_materials(QUICConnectionId cid) = 0;
+ virtual int initialize_key_materials(QUICConnectionId cid, QUICVersion) = 0;
virtual const char *negotiated_cipher_suite() const = 0;
virtual void negotiated_application_name(const uint8_t **name, unsigned int *len) const = 0;
diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc
index 24c2b84..7ac32ba 100644
--- a/iocore/net/quic/QUICKeyGenerator.cc
+++ b/iocore/net/quic/QUICKeyGenerator.cc
@@ -34,6 +34,9 @@
using namespace std::literals;
constexpr static uint8_t QUIC_VERSION_1_SALT[] = {
+ 0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99,
+};
+constexpr static uint8_t QUIC_VERSION_1_D27_SALT[] = {
0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb, 0x5a, 0x11, 0xa7, 0xd2, 0x43, 0x2b, 0xb4, 0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02,
};
constexpr static std::string_view LABEL_FOR_CLIENT_INITIAL_SECRET("client in"sv);
@@ -43,7 +46,7 @@ constexpr static std::string_view LABEL_FOR_IV("quic iv"sv);
constexpr static std::string_view LABEL_FOR_HP("quic hp"sv);
void
-QUICKeyGenerator::generate(uint8_t *hp_key, uint8_t *pp_key, uint8_t *iv, size_t *iv_len, QUICConnectionId cid)
+QUICKeyGenerator::generate(QUICVersion version, uint8_t *hp_key, uint8_t *pp_key, uint8_t *iv, size_t *iv_len, QUICConnectionId cid)
{
const EVP_CIPHER *cipher = this->_get_cipher_for_initial();
const EVP_MD *md = EVP_sha256();
@@ -53,7 +56,7 @@ QUICKeyGenerator::generate(uint8_t *hp_key, uint8_t *pp_key, uint8_t *iv, size_t
switch (this->_ctx) {
case Context::CLIENT:
- this->_generate_initial_secret(secret, &secret_len, hkdf, cid, LABEL_FOR_CLIENT_INITIAL_SECRET.data(),
+ this->_generate_initial_secret(version, secret, &secret_len, hkdf, cid, LABEL_FOR_CLIENT_INITIAL_SECRET.data(),
LABEL_FOR_CLIENT_INITIAL_SECRET.length(), EVP_MD_size(md));
if (is_debug_tag_set("vv_quic_crypto")) {
uint8_t print_buf[1024 + 1];
@@ -63,7 +66,7 @@ QUICKeyGenerator::generate(uint8_t *hp_key, uint8_t *pp_key, uint8_t *iv, size_t
break;
case Context::SERVER:
- this->_generate_initial_secret(secret, &secret_len, hkdf, cid, LABEL_FOR_SERVER_INITIAL_SECRET.data(),
+ this->_generate_initial_secret(version, secret, &secret_len, hkdf, cid, LABEL_FOR_SERVER_INITIAL_SECRET.data(),
LABEL_FOR_SERVER_INITIAL_SECRET.length(), EVP_MD_size(md));
if (is_debug_tag_set("vv_quic_crypto")) {
uint8_t print_buf[1024 + 1];
@@ -101,18 +104,33 @@ QUICKeyGenerator::_generate(uint8_t *hp_key, uint8_t *pp_key, uint8_t *iv, size_
}
int
-QUICKeyGenerator::_generate_initial_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, QUICConnectionId cid, const char *label,
- size_t label_len, size_t length)
+QUICKeyGenerator::_generate_initial_secret(QUICVersion version, uint8_t *out, size_t *out_len, QUICHKDF &hkdf, QUICConnectionId cid,
+ const char *label, size_t label_len, size_t length)
{
uint8_t client_connection_id[QUICConnectionId::MAX_LENGTH];
size_t cid_len = 0;
uint8_t initial_secret[512];
size_t initial_secret_len = sizeof(initial_secret);
+ const uint8_t *salt;
+ size_t salt_len;
// TODO: do not extract initial secret twice
QUICTypeUtil::write_QUICConnectionId(cid, client_connection_id, &cid_len);
- if (hkdf.extract(initial_secret, &initial_secret_len, QUIC_VERSION_1_SALT, sizeof(QUIC_VERSION_1_SALT), client_connection_id,
- cid.length()) != 1) {
+ switch (version) {
+ case 0xff00001d: // Draft-29
+ salt = QUIC_VERSION_1_SALT;
+ salt_len = sizeof(QUIC_VERSION_1_SALT);
+ break;
+ case 0xff00001b: // Draft-27
+ salt = QUIC_VERSION_1_D27_SALT;
+ salt_len = sizeof(QUIC_VERSION_1_D27_SALT);
+ break;
+ default:
+ salt = QUIC_VERSION_1_SALT;
+ salt_len = sizeof(QUIC_VERSION_1_SALT);
+ break;
+ }
+ if (hkdf.extract(initial_secret, &initial_secret_len, salt, salt_len, client_connection_id, cid.length()) != 1) {
return -1;
}
diff --git a/iocore/net/quic/QUICKeyGenerator.h b/iocore/net/quic/QUICKeyGenerator.h
index c2ff89f..db2924c 100644
--- a/iocore/net/quic/QUICKeyGenerator.h
+++ b/iocore/net/quic/QUICKeyGenerator.h
@@ -43,7 +43,7 @@ public:
* Generate keys for Initial encryption level
* The keys for the remaining encryption level are derived by TLS stack with "quic " prefix
*/
- void generate(uint8_t *hp_key, uint8_t *pp_key, uint8_t *iv, size_t *iv_len, QUICConnectionId cid);
+ void generate(QUICVersion version, uint8_t *hp_key, uint8_t *pp_key, uint8_t *iv, size_t *iv_len, QUICConnectionId cid);
void regenerate(uint8_t *hp_key, uint8_t *pp_key, uint8_t *iv, size_t *iv_len, const uint8_t *secret, size_t secret_len,
const EVP_CIPHER *cipher, QUICHKDF &hkdf);
@@ -56,8 +56,8 @@ private:
int _generate(uint8_t *hp_key, uint8_t *pp_key, uint8_t *iv, size_t *iv_len, QUICHKDF &hkdf, const uint8_t *secret,
size_t secret_len, const EVP_CIPHER *cipher);
- int _generate_initial_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, QUICConnectionId cid, const char *label,
- size_t label_len, size_t length);
+ int _generate_initial_secret(QUICVersion version, uint8_t *out, size_t *out_len, QUICHKDF &hkdf, QUICConnectionId cid,
+ const char *label, size_t label_len, size_t length);
int _generate_key(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len,
size_t key_length) const;
int _generate_iv(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t iv_length) const;
diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc
index 3d381b2..a52ec68 100644
--- a/iocore/net/quic/QUICLossDetector.cc
+++ b/iocore/net/quic/QUICLossDetector.cc
@@ -61,7 +61,7 @@ QUICLossDetector::~QUICLossDetector()
this->_loss_detection_timer = nullptr;
}
- for (auto i = 0; i < kPacketNumberSpace; i++) {
+ for (auto i = 0; i < QUIC_N_PACKET_SPACES; i++) {
this->_sent_packets[i].clear();
}
}
@@ -125,32 +125,30 @@ QUICLossDetector::largest_acked_packet_number(QUICPacketNumberSpace pn_space) co
}
void
-QUICLossDetector::on_packet_sent(QUICPacketInfoUPtr packet_info, bool in_flight)
+QUICLossDetector::on_packet_sent(QUICSentPacketInfoUPtr packet_info, bool in_flight)
{
+ // ADDITIONAL CODE
if (packet_info->type == QUICPacketType::VERSION_NEGOTIATION) {
return;
}
+ // END OF ADDITIONAL CODE
SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread());
QUICPacketNumber packet_number = packet_info->packet_number;
bool ack_eliciting = packet_info->ack_eliciting;
- bool is_crypto_packet = packet_info->is_crypto_packet;
ink_hrtime now = packet_info->time_sent;
size_t sent_bytes = packet_info->sent_bytes;
+ QUICPacketNumberSpace pn_space = packet_info->pn_space;
- QUICLDDebug("%s packet sent : %" PRIu64 " bytes: %lu ack_eliciting: %d", QUICDebugNames::pn_space(packet_info->pn_space),
- packet_number, sent_bytes, ack_eliciting);
+ QUICLDVDebug("%s packet sent : %" PRIu64 " bytes: %lu ack_eliciting: %d", QUICDebugNames::pn_space(packet_info->pn_space),
+ packet_number, sent_bytes, ack_eliciting);
this->_add_to_sent_packet_list(packet_number, std::move(packet_info));
if (in_flight) {
- if (is_crypto_packet) {
- this->_time_of_last_sent_crypto_packet = now;
- }
-
if (ack_eliciting) {
- this->_time_of_last_sent_ack_eliciting_packet = now;
+ this->_time_of_last_ack_eliciting_packet[static_cast<int>(pn_space)] = now;
}
this->_cc->on_packet_sent(sent_bytes);
this->_set_loss_detection_timer();
@@ -158,27 +156,60 @@ QUICLossDetector::on_packet_sent(QUICPacketInfoUPtr packet_info, bool in_flight)
}
void
+QUICLossDetector::on_datagram_received()
+{
+ if (this->_context.connection_info()->is_at_anti_amplification_limit()) {
+ this->_set_loss_detection_timer();
+ }
+}
+
+void
+QUICLossDetector::on_packet_number_space_discarded(QUICPacketNumberSpace pn_space)
+{
+ ink_assert(pn_space != QUICPacketNumberSpace::APPLICATION_DATA);
+ size_t bytes_in_flight = 0;
+ for (auto it = this->_sent_packets[static_cast<int>(pn_space)].begin();
+ it != this->_sent_packets[static_cast<int>(pn_space)].end();) {
+ auto ret = this->_remove_from_sent_packet_list(it, pn_space);
+ auto &pi = ret.first;
+ if (pi->in_flight) {
+ bytes_in_flight += pi->sent_bytes;
+ }
+ it = ret.second;
+ }
+ this->_cc->on_packet_number_space_discarded(bytes_in_flight);
+ // Reset the loss detection and PTO timer
+ this->_time_of_last_ack_eliciting_packet[static_cast<int>(pn_space)] = 0;
+ this->_loss_time[static_cast<int>(pn_space)] = 0;
+ this->_rtt_measure->set_pto_count(0);
+ this->_set_loss_detection_timer();
+ QUICLDDebug("[%s] Packets have been discarded because keys for the space are discarded", QUICDebugNames::pn_space(pn_space));
+}
+
+void
QUICLossDetector::reset()
{
SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread());
+
+ // A.4. Initialization
if (this->_loss_detection_timer) {
this->_loss_detection_timer->cancel();
this->_loss_detection_timer = nullptr;
}
-
- this->_ack_eliciting_outstanding = 0;
- this->_crypto_outstanding = 0;
-
- // [draft-17 recovery] 6.4.3. Initialization
- this->_time_of_last_sent_ack_eliciting_packet = 0;
- this->_time_of_last_sent_crypto_packet = 0;
- for (auto i = 0; i < kPacketNumberSpace; i++) {
- this->_largest_acked_packet[i] = 0;
- this->_loss_time[i] = 0;
+ this->_rtt_measure->reset();
+ for (auto i = 0; i < QUIC_N_PACKET_SPACES; i++) {
+ this->_largest_acked_packet[i] = UINT64_MAX;
+ this->_time_of_last_ack_eliciting_packet[i] = 0;
+ this->_loss_time[i] = 0;
this->_sent_packets[i].clear();
+ // ADDITIONAL CODE
+ this->_num_packets_in_flight[i] = 0;
+ // END OF ADDITIONAL CODE
}
- this->_rtt_measure->reset();
+ // ADDITIONAL CODE
+ this->_ack_eliciting_outstanding = 0;
+ // END OF ADDITIONAL CODE
}
void
@@ -188,12 +219,12 @@ QUICLossDetector::update_ack_delay_exponent(uint8_t ack_delay_exponent)
}
bool
-QUICLossDetector::_include_ack_eliciting(const std::vector<QUICPacketInfo *> &acked_packets, int index) const
+QUICLossDetector::_include_ack_eliciting(const std::vector<QUICSentPacketInfoUPtr> &acked_packets) const
{
// Find out ack_elicting packet.
// FIXME: this loop is the same as _on_ack_received's loop it would better
// to combine it.
- for (auto packet : acked_packets) {
+ for (const auto &packet : acked_packets) {
if (packet->ack_eliciting) {
return true;
}
@@ -207,65 +238,68 @@ QUICLossDetector::_on_ack_received(const QUICAckFrame &ack_frame, QUICPacketNumb
{
SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread());
- int index = static_cast<int>(pn_space);
- this->_largest_acked_packet[index] = std::max(this->_largest_acked_packet[index], ack_frame.largest_acknowledged());
+ int index = static_cast<int>(pn_space);
+ if (this->_largest_acked_packet[index] == UINT64_MAX) {
+ this->_largest_acked_packet[index] = ack_frame.largest_acknowledged();
+ } else {
+ this->_largest_acked_packet[index] = std::max(this->_largest_acked_packet[index], ack_frame.largest_acknowledged());
+ }
- auto newly_acked_packets = this->_determine_newly_acked_packets(ack_frame, index);
+ auto newly_acked_packets = this->_detect_and_remove_acked_packets(ack_frame, pn_space);
if (newly_acked_packets.empty()) {
return;
}
// If the largest acknowledged is newly acked and
// ack-eliciting, update the RTT.
- auto pi = this->_sent_packets[index].find(ack_frame.largest_acknowledged());
- if (pi != this->_sent_packets[index].end() &&
- (pi->second->ack_eliciting || this->_include_ack_eliciting(newly_acked_packets, index))) {
- ink_hrtime latest_rtt = Thread::get_hrtime() - pi->second->time_sent;
+ const auto &largest_acked = newly_acked_packets[0];
+ if (largest_acked->packet_number == ack_frame.largest_acknowledged() && this->_include_ack_eliciting(newly_acked_packets)) {
+ ink_hrtime latest_rtt = Thread::get_hrtime() - largest_acked->time_sent;
// _latest_rtt is nanosecond but ack_frame.ack_delay is microsecond and scaled
- ink_hrtime delay = HRTIME_USECONDS(ack_frame.ack_delay() << this->_ack_delay_exponent);
- this->_rtt_measure->update_rtt(latest_rtt, delay);
+ ink_hrtime ack_delay = 0;
+ if (pn_space == QUICPacketNumberSpace::APPLICATION_DATA) {
+ ack_delay = HRTIME_USECONDS(ack_frame.ack_delay() << this->_ack_delay_exponent);
+ }
+ this->_rtt_measure->update_rtt(latest_rtt, ack_delay);
}
- QUICLDVDebug("[%s] Unacked packets %lu (retransmittable %u, includes %u handshake packets)", QUICDebugNames::pn_space(pn_space),
- this->_sent_packets[index].size(), this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load());
-
// if (ACK frame contains ECN information):
// ProcessECN(ack)
- if (ack_frame.ecn_section() != nullptr && pi != this->_sent_packets[index].end()) {
- this->_cc->process_ecn(*pi->second, ack_frame.ecn_section());
+ if (ack_frame.ecn_section() != nullptr) {
+ this->_cc->process_ecn(ack_frame, pn_space, largest_acked->time_sent);
}
+ // ADDITIONAL CODE
// Find all newly acked packets.
- for (auto info : newly_acked_packets) {
+ for (const auto &info : newly_acked_packets) {
this->_on_packet_acked(*info);
}
+ // END OF ADDITIONAL CODE
- QUICLDVDebug("[%s] Unacked packets %lu (retransmittable %u, includes %u handshake packets)", QUICDebugNames::pn_space(pn_space),
- this->_sent_packets[index].size(), this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load());
-
- this->_detect_lost_packets(pn_space);
-
- this->_rtt_measure->set_crypto_count(0);
- this->_rtt_measure->set_pto_count(0);
+ auto lost_packets = this->_detect_and_remove_lost_packets(pn_space);
+ if (!lost_packets.empty()) {
+ this->_cc->on_packets_lost(lost_packets);
+ }
+ this->_cc->on_packets_acked(newly_acked_packets);
- QUICLDDebug("[%s] Unacked packets %lu (retransmittable %u, includes %u handshake packets)", QUICDebugNames::pn_space(pn_space),
- this->_sent_packets[index].size(), this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load());
+ QUICLDVDebug("[%s] Newly acked:%lu Lost:%lu Unacked packets:%lu (%u ack eliciting)", QUICDebugNames::pn_space(pn_space),
+ newly_acked_packets.size(), lost_packets.size(), this->_sent_packets[index].size(),
+ this->_ack_eliciting_outstanding.load());
+ if (this->_peer_completed_address_validation()) {
+ this->_rtt_measure->set_pto_count(0);
+ }
this->_set_loss_detection_timer();
}
void
-QUICLossDetector::_on_packet_acked(const QUICPacketInfo &acked_packet)
+QUICLossDetector::_on_packet_acked(const QUICSentPacketInfo &acked_packet)
{
SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread());
- QUICLDDebug("[%s] Packet number %" PRIu64 " has been acked", QUICDebugNames::pn_space(acked_packet.pn_space),
- acked_packet.packet_number);
-
- if (acked_packet.in_flight) {
- this->_cc->on_packet_acked(acked_packet);
- }
+ QUICLDVDebug("[%s] Packet number %" PRIu64 " has been acked", QUICDebugNames::pn_space(acked_packet.pn_space),
+ acked_packet.packet_number);
- for (const QUICFrameInfo &frame_info : acked_packet.frames) {
+ for (const QUICSentPacketInfo::FrameInfo &frame_info : acked_packet.frames) {
auto reactor = frame_info.generated_by();
if (reactor == nullptr) {
continue;
@@ -273,17 +307,15 @@ QUICLossDetector::_on_packet_acked(const QUICPacketInfo &acked_packet)
reactor->on_frame_acked(frame_info.id());
}
-
- this->_remove_from_sent_packet_list(acked_packet.packet_number, acked_packet.pn_space);
}
ink_hrtime
-QUICLossDetector::_get_earliest_loss_time(QUICPacketNumberSpace &pn_space)
+QUICLossDetector::_get_loss_time_and_space(QUICPacketNumberSpace &pn_space)
{
- ink_hrtime time = this->_loss_time[static_cast<int>(QUICPacketNumberSpace::Initial)];
- pn_space = QUICPacketNumberSpace::Initial;
- for (auto i = 1; i < kPacketNumberSpace; i++) {
- if (this->_loss_time[i] != 0 && (time != 0 || this->_loss_time[i] < time)) {
+ ink_hrtime time = this->_loss_time[static_cast<int>(QUICPacketNumberSpace::INITIAL)];
+ pn_space = QUICPacketNumberSpace::INITIAL;
+ for (auto i = 1; i < QUIC_N_PACKET_SPACES; i++) {
+ if (time == 0 || this->_loss_time[i] < time) {
time = this->_loss_time[i];
pn_space = static_cast<QUICPacketNumberSpace>(i);
}
@@ -292,6 +324,59 @@ QUICLossDetector::_get_earliest_loss_time(QUICPacketNumberSpace &pn_space)
return time;
}
+ink_hrtime
+QUICLossDetector::_get_pto_time_and_space(QUICPacketNumberSpace &space)
+{
+ ink_hrtime duration =
+ (this->_rtt_measure->smoothed_rtt() + std::max(4 * this->_rtt_measure->rttvar(), this->_rtt_measure->k_granularity())) *
+ (1 << this->_rtt_measure->pto_count());
+
+ // Arm PTO from now when there are no inflight packets.
+ if (this->_num_packets_in_flight[static_cast<int>(QUICPacketNumberSpace::INITIAL)].load() == 0 &&
+ this->_num_packets_in_flight[static_cast<int>(QUICPacketNumberSpace::HANDSHAKE)].load() == 0 &&
+ this->_num_packets_in_flight[static_cast<int>(QUICPacketNumberSpace::APPLICATION_DATA)].load() == 0) {
+ ink_assert(!this->_peer_completed_address_validation());
+ if (this->_context.connection_info()->has_keys_for(QUICPacketNumberSpace::HANDSHAKE)) {
+ space = QUICPacketNumberSpace::HANDSHAKE;
+ return Thread::get_hrtime() + duration;
+ } else {
+ space = QUICPacketNumberSpace::INITIAL;
+ return Thread::get_hrtime() + duration;
+ }
+ }
+ ink_hrtime pto_timeout = INT64_MAX;
+ QUICPacketNumberSpace pto_space = QUICPacketNumberSpace::INITIAL;
+ for (int i = 0; i < QUIC_N_PACKET_SPACES; ++i) {
+ if (this->_num_packets_in_flight[i].load() == 0) {
+ continue;
+ }
+ if (i == static_cast<int>(QUICPacketNumberSpace::APPLICATION_DATA)) {
+ // Skip ApplicationData until handshake complete.
+ if (!this->_context.connection_info()->is_address_validation_completed()) {
+ space = pto_space;
+ return pto_timeout;
+ }
+ // Include max_ack_delay and backoff for ApplicationData.
+ // FIXME should be set by transport parameters
+ duration += this->_rtt_measure->max_ack_delay() * (1 << this->_rtt_measure->pto_count());
+ }
+
+ ink_hrtime t = this->_time_of_last_ack_eliciting_packet[i] + duration;
+ if (t < pto_timeout) {
+ pto_timeout = t;
+ pto_space = QUICPacketNumberSpace(i);
+ }
+ }
+ space = pto_space;
+ return pto_timeout;
+}
+
+bool
+QUICLossDetector::_peer_completed_address_validation() const
+{
+ return this->_context.connection_info()->is_address_validation_completed();
+}
+
void
QUICLossDetector::_set_loss_detection_timer()
{
@@ -302,112 +387,115 @@ QUICLossDetector::_set_loss_detection_timer()
}
};
+ std::function<void(void)> cancel_timer = [this]() {
+ this->_loss_detection_alarm_at = 0;
+ this->_loss_detection_timer->cancel();
+ this->_loss_detection_timer = nullptr;
+ };
+
QUICPacketNumberSpace pn_space;
- ink_hrtime alarm = this->_get_earliest_loss_time(pn_space);
- if (alarm != 0) {
- update_timer(alarm);
+ ink_hrtime earliest_loss_time = this->_get_loss_time_and_space(pn_space);
+ if (earliest_loss_time != 0) {
+ update_timer(earliest_loss_time);
QUICLDDebug("[%s] time threshold loss detection timer: %" PRId64 "ms", QUICDebugNames::pn_space(pn_space),
(this->_loss_detection_alarm_at - Thread::get_hrtime()) / HRTIME_MSECOND);
return;
}
- if (this->_crypto_outstanding > 0 || this->_is_client_without_one_rtt_key()) {
- // Crypto retransmission timer.
- alarm = this->_time_of_last_sent_crypto_packet + this->_rtt_measure->handshake_retransmit_timeout();
- update_timer(alarm);
- QUICLDDebug("%s crypto packet alarm will be set: %" PRId64 "ms", QUICDebugNames::pn_space(pn_space),
- (alarm - this->_time_of_last_sent_crypto_packet) / HRTIME_MSECOND);
- return;
+ if (this->_context.connection_info()->is_at_anti_amplification_limit()) {
+ if (this->_loss_detection_timer) {
+ cancel_timer();
+ QUICLDDebug("Loss detection alarm has been unset because of anti-amplification limit");
+ return;
+ }
}
// Don't arm the alarm if there are no packets with retransmittable data in flight.
- // -- MODIFIED CODE --
- // In pseudocode, `bytes_in_flight` is used, but we're tracking "retransmittable data in flight" by `_ack_eliciting_outstanding`
- if (this->_ack_eliciting_outstanding == 0) {
+ if (this->_ack_eliciting_outstanding == 0 && this->_peer_completed_address_validation()) {
if (this->_loss_detection_timer) {
- this->_loss_detection_alarm_at = 0;
- this->_loss_detection_timer->cancel();
- this->_loss_detection_timer = nullptr;
- QUICLDDebug("Loss detection alarm has been unset");
+ cancel_timer();
+ QUICLDDebug("Loss detection alarm has been unset because of no ack eliciting packets outstanding");
}
-
return;
}
- // -- END OF MODIFIED CODE --
// PTO Duration
- alarm = this->_time_of_last_sent_ack_eliciting_packet + this->_rtt_measure->current_pto_period();
- update_timer(alarm);
- QUICLDDebug("[%s] PTO timeout will be set: %" PRId64 "ms", QUICDebugNames::pn_space(pn_space),
- (alarm - this->_time_of_last_sent_ack_eliciting_packet) / HRTIME_MSECOND);
+ ink_hrtime timeout = this->_get_pto_time_and_space(pn_space);
+ update_timer(timeout);
+ QUICLDVDebug("[%s] PTO timeout has been set: %" PRId64 "ms", QUICDebugNames::pn_space(pn_space),
+ (timeout - this->_time_of_last_ack_eliciting_packet[static_cast<int>(pn_space)]) / HRTIME_MSECOND);
}
void
QUICLossDetector::_on_loss_detection_timeout()
{
QUICPacketNumberSpace pn_space;
- ink_hrtime loss_time = this->_get_earliest_loss_time(pn_space);
- if (loss_time != 0) {
+ ink_hrtime earliest_loss_time = this->_get_loss_time_and_space(pn_space);
+ if (earliest_loss_time != 0) {
// Time threshold loss Detection
- this->_detect_lost_packets(pn_space);
- } else if (this->_crypto_outstanding) {
- // Handshake retransmission alarm.
- QUICLDVDebug("Crypto Retranmission");
- this->_retransmit_all_unacked_crypto_data();
- this->_rtt_measure->set_crypto_count(this->_rtt_measure->crypto_count() + 1);
- } else if (this->_is_client_without_one_rtt_key()) {
+ auto lost_packets = this->_detect_and_remove_lost_packets(pn_space);
+ ink_assert(!lost_packets.empty());
+ this->_cc->on_packets_lost(lost_packets);
+ this->_set_loss_detection_timer();
+ return;
+ }
+
+ if (this->_cc->bytes_in_flight() > 0) {
+ // PTO. Send new data if available, else retransmit old data.
+ // If neither is available, send a single PING frame.
+ QUICPacketNumberSpace pns;
+ this->_get_pto_time_and_space(pns);
+ this->_send_one_or_two_ack_eliciting_packet(pns);
+ } else {
+ ink_assert(this->_is_client_without_one_rtt_key());
// Client sends an anti-deadlock packet: Initial is padded
// to earn more anti-amplification credit,
// a Handshake packet proves address ownership.
if (this->_context.key_info()->is_encryption_key_available(QUICKeyPhase::HANDSHAKE)) {
- this->_send_one_handshake_packets();
+ this->_send_one_ack_eliciting_handshake_packet();
} else {
- this->_send_one_padded_packets();
+ this->_send_one_ack_eliciting_padded_initial_packet();
}
-
- this->_rtt_measure->set_crypto_count(this->_rtt_measure->crypto_count() + 1);
- } else {
- QUICLDVDebug("PTO");
- this->_send_one_or_two_packet();
- this->_rtt_measure->set_pto_count(this->_rtt_measure->pto_count() + 1);
}
- QUICLDDebug("[%s] Unacked packets %lu (retransmittable %u, includes %u handshake packets)", QUICDebugNames::pn_space(pn_space),
- this->_sent_packets[static_cast<int>(pn_space)].size(), this->_ack_eliciting_outstanding.load(),
- this->_crypto_outstanding.load());
+ this->_rtt_measure->set_pto_count(this->_rtt_measure->pto_count() + 1);
+ this->_set_loss_detection_timer();
+
+ QUICLDDebug("[%s] Unacked packets %lu (ack_eliciting %u)", QUICDebugNames::pn_space(pn_space),
+ this->_sent_packets[static_cast<int>(pn_space)].size(), this->_ack_eliciting_outstanding.load());
if (is_debug_tag_set("v_quic_loss_detector")) {
for (auto i = 0; i < 3; i++) {
for (auto &unacked : this->_sent_packets[i]) {
- QUICLDVDebug("[%s] #%" PRIu64 " is_crypto=%i ack_eliciting=%i size=%zu %u %u",
- QUICDebugNames::pn_space(static_cast<QUICPacketNumberSpace>(i)), unacked.first,
- unacked.second->is_crypto_packet, unacked.second->ack_eliciting, unacked.second->sent_bytes,
- this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load());
+ QUICLDVDebug("[%s] #%" PRIu64 " ack_eliciting=%i size=%zu %u",
+ QUICDebugNames::pn_space(static_cast<QUICPacketNumberSpace>(i)), unacked.first, unacked.second->ack_eliciting,
+ unacked.second->sent_bytes, this->_ack_eliciting_outstanding.load());
}
}
}
-
- this->_set_loss_detection_timer();
}
-void
-QUICLossDetector::_detect_lost_packets(QUICPacketNumberSpace pn_space)
+std::map<QUICPacketNumber, QUICSentPacketInfoUPtr>
+QUICLossDetector::_detect_and_remove_lost_packets(QUICPacketNumberSpace pn_space)
{
SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread());
+ ink_assert(this->_largest_acked_packet[static_cast<int>(pn_space)] != UINT64_MAX);
+
this->_loss_time[static_cast<int>(pn_space)] = 0;
+ std::map<QUICPacketNumber, QUICSentPacketInfoUPtr> lost_packets;
ink_hrtime loss_delay = this->_k_time_threshold * std::max(this->_rtt_measure->latest_rtt(), this->_rtt_measure->smoothed_rtt());
- loss_delay = std::min(loss_delay, this->_rtt_measure->k_granularity());
- std::map<QUICPacketNumber, QUICPacketInfo *> lost_packets;
+ // Minimum time of kGranularity before packets are deemed lost.
+ loss_delay = std::max(loss_delay, this->_rtt_measure->k_granularity());
// Packets sent before this time are deemed lost.
ink_hrtime lost_send_time = Thread::get_hrtime() - loss_delay;
// Packets with packet numbers before this are deemed lost.
- QUICPacketNumber lost_pn = this->_largest_acked_packet[static_cast<int>(pn_space)] - this->_k_packet_threshold;
+ // QUICPacketNumber lost_pn = this->_largest_acked_packet[static_cast<int>(pn_space)] - this->_k_packet_threshold;
for (auto it = this->_sent_packets[static_cast<int>(pn_space)].begin();
- it != this->_sent_packets[static_cast<int>(pn_space)].end(); ++it) {
+ it != this->_sent_packets[static_cast<int>(pn_space)].end();) {
if (it->first > this->_largest_acked_packet[static_cast<int>(pn_space)]) {
// the spec uses continue but we can break here because the _sent_packets is sorted by packet_number.
break;
@@ -416,8 +504,9 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumberSpace pn_space)
auto &unacked = it->second;
// Mark packet as lost, or set time when it should be marked.
- if (unacked->time_sent < lost_send_time || unacked->packet_number < lost_pn) {
- if (unacked->time_sent < lost_send_time) {
+ if (unacked->time_sent <= lost_send_time ||
+ this->_largest_acked_packet[static_cast<int>(pn_space)] >= unacked->packet_number + this->_k_packet_threshold) {
+ if (unacked->time_sent <= lost_send_time) {
QUICLDDebug("[%s] Lost: time since sent is too long (#%" PRId64 " sent=%" PRId64 ", delay=%" PRId64
", fraction=%lf, lrtt=%" PRId64 ", srtt=%" PRId64 ")",
QUICDebugNames::pn_space(pn_space), it->first, unacked->time_sent, lost_send_time, this->_k_time_threshold,
@@ -428,61 +517,42 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumberSpace pn_space)
this->_k_packet_threshold);
}
- if (unacked->in_flight) {
- lost_packets.insert({it->first, it->second.get()});
+ auto ret = this->_remove_from_sent_packet_list(it, pn_space);
+ auto pi = std::move(ret.first);
+ it = ret.second;
+ if (pi->in_flight) {
+ this->_context.trigger(QUICContext::CallbackEvent::PACKET_LOST, *pi);
+ lost_packets.emplace(pi->packet_number, std::move(pi));
}
- } else if (this->_loss_time[static_cast<int>(pn_space)] == 0) {
- this->_loss_time[static_cast<int>(pn_space)] = unacked->time_sent + loss_delay;
+
} else {
- this->_loss_time[static_cast<int>(pn_space)] =
- std::min(this->_loss_time[static_cast<int>(pn_space)], unacked->time_sent + loss_delay);
+ if (this->_loss_time[static_cast<int>(pn_space)] == 0) {
+ this->_loss_time[static_cast<int>(pn_space)] = unacked->time_sent + loss_delay;
+ } else {
+ this->_loss_time[static_cast<int>(pn_space)] =
+ std::min(this->_loss_time[static_cast<int>(pn_space)], unacked->time_sent + loss_delay);
+ }
+ ++it;
}
}
- // Inform the congestion controller of lost packets and
- // lets it decide whether to retransmit immediately.
+ // -- ADDITIONAL CODE --
+ // Not sure how we can get feedback from congestion control and when we should retransmit the lost packets but we need to send
+ // them somewhere.
+ // I couldn't find the place so just send them here for now.
if (!lost_packets.empty()) {
- this->_cc->on_packets_lost(lost_packets);
- for (auto lost_packet : lost_packets) {
- this->_context.trigger(QUICContext::CallbackEvent::PACKET_LOST, *lost_packet.second);
- // -- ADDITIONAL CODE --
- // Not sure how we can get feedback from congestion control and when we should retransmit the lost packets but we need to send
- // them somewhere.
- // I couldn't find the place so just send them here for now.
+ for (const auto &lost_packet : lost_packets) {
this->_retransmit_lost_packet(*lost_packet.second);
- // -- END OF ADDITIONAL CODE --
- // -- ADDITIONAL CODE --
- this->_remove_from_sent_packet_list(lost_packet.first, pn_space);
- // -- END OF ADDITIONAL CODE --
}
}
+ // -- END OF ADDITIONAL CODE --
+
+ return lost_packets;
}
// ===== Functions below are used on the spec but there're no pseudo code =====
void
-QUICLossDetector::_retransmit_all_unacked_crypto_data()
-{
- SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread());
- for (auto i = 0; i < kPacketNumberSpace; i++) {
- std::set<QUICPacketNumber> retransmitted_crypto_packets;
- std::map<QUICPacketNumber, QUICPacketInfo *> lost_packets;
- for (auto &info : this->_sent_packets[i]) {
- if (info.second->is_crypto_packet) {
- retransmitted_crypto_packets.insert(info.first);
- this->_retransmit_lost_packet(*info.second);
- lost_packets.insert({info.first, info.second.get()});
- }
- }
-
- this->_cc->on_packets_lost(lost_packets);
- for (auto packet_number : retransmitted_crypto_packets) {
- this->_remove_from_sent_packet_list(packet_number, static_cast<QUICPacketNumberSpace>(i));
- }
- }
-}
-
-void
QUICLossDetector::_send_packet(QUICEncryptionLevel level, bool padded)
{
if (padded) {
@@ -494,7 +564,7 @@ QUICLossDetector::_send_packet(QUICEncryptionLevel level, bool padded)
}
void
-QUICLossDetector::_send_one_or_two_packet()
+QUICLossDetector::_send_one_or_two_ack_eliciting_packet(QUICPacketNumberSpace pn_space)
{
this->_send_packet(QUICEncryptionLevel::ONE_RTT);
this->_send_packet(QUICEncryptionLevel::ONE_RTT);
@@ -504,7 +574,7 @@ QUICLossDetector::_send_one_or_two_packet()
}
void
-QUICLossDetector::_send_one_handshake_packets()
+QUICLossDetector::_send_one_ack_eliciting_handshake_packet()
{
this->_send_packet(QUICEncryptionLevel::HANDSHAKE);
QUICLDDebug("[%s] send handshake packet: ping count=%" PRIu64, QUICDebugNames::encryption_level(QUICEncryptionLevel::HANDSHAKE),
@@ -512,7 +582,7 @@ QUICLossDetector::_send_one_handshake_packets()
}
void
-QUICLossDetector::_send_one_padded_packets()
+QUICLossDetector::_send_one_ack_eliciting_padded_initial_packet()
{
this->_send_packet(QUICEncryptionLevel::INITIAL, true);
QUICLDDebug("[%s] send PADDING frame: ping count=%" PRIu64, QUICDebugNames::encryption_level(QUICEncryptionLevel::INITIAL),
@@ -522,12 +592,12 @@ QUICLossDetector::_send_one_padded_packets()
// ===== Functions below are helper functions =====
void
-QUICLossDetector::_retransmit_lost_packet(const QUICPacketInfo &packet_info)
+QUICLossDetector::_retransmit_lost_packet(const QUICSentPacketInfo &packet_info)
{
SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread());
QUICLDDebug("Retransmit %s packet #%" PRIu64, QUICDebugNames::packet_type(packet_info.type), packet_info.packet_number);
- for (const QUICFrameInfo &frame_info : packet_info.frames) {
+ for (const QUICSentPacketInfo::FrameInfo &frame_info : packet_info.frames) {
auto reactor = frame_info.generated_by();
if (reactor == nullptr) {
continue;
@@ -537,11 +607,13 @@ QUICLossDetector::_retransmit_lost_packet(const QUICPacketInfo &packet_info)
}
}
-std::vector<QUICPacketInfo *>
-QUICLossDetector::_determine_newly_acked_packets(const QUICAckFrame &ack_frame, int pn_space)
+std::vector<QUICSentPacketInfoUPtr>
+QUICLossDetector::_detect_and_remove_acked_packets(const QUICAckFrame &ack_frame, QUICPacketNumberSpace pn_space)
{
- std::vector<QUICPacketInfo *> packets;
+ std::vector<QUICSentPacketInfoUPtr> packets;
std::set<QUICAckFrame::PacketNumberRange> numbers;
+ int index = static_cast<int>(pn_space);
+
QUICPacketNumber x = ack_frame.largest_acknowledged();
numbers.insert({x, static_cast<uint64_t>(x) - ack_frame.ack_block_section()->first_ack_block()});
x -= ack_frame.ack_block_section()->first_ack_block() + 1;
@@ -552,9 +624,13 @@ QUICLossDetector::_determine_newly_acked_packets(const QUICAckFrame &ack_frame,
}
for (auto &&range : numbers) {
- for (auto ite = this->_sent_packets[pn_space].rbegin(); ite != this->_sent_packets[pn_space].rend(); ite++) {
+ for (auto ite = this->_sent_packets[index].begin(); ite != this->_sent_packets[index].end();) {
if (range.contains(ite->first)) {
- packets.push_back(ite->second.get());
+ auto ret = this->_remove_from_sent_packet_list(ite, pn_space);
+ packets.push_back(std::move(ret.first));
+ ite = ret.second;
+ } else {
+ ++ite;
}
}
}
@@ -563,62 +639,48 @@ QUICLossDetector::_determine_newly_acked_packets(const QUICAckFrame &ack_frame,
}
void
-QUICLossDetector::_add_to_sent_packet_list(QUICPacketNumber packet_number, QUICPacketInfoUPtr packet_info)
+QUICLossDetector::_add_to_sent_packet_list(QUICPacketNumber packet_number, QUICSentPacketInfoUPtr packet_info)
{
SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread());
// Add to the list
int index = static_cast<int>(packet_info->pn_space);
- this->_sent_packets[index].insert(std::pair<QUICPacketNumber, QUICPacketInfoUPtr>(packet_number, std::move(packet_info)));
+ this->_sent_packets[index].insert(std::pair<QUICPacketNumber, QUICSentPacketInfoUPtr>(packet_number, std::move(packet_info)));
// Increment counters
auto ite = this->_sent_packets[index].find(packet_number);
if (ite != this->_sent_packets[index].end()) {
- if (ite->second->is_crypto_packet) {
- ++this->_crypto_outstanding;
- ink_assert(this->_crypto_outstanding.load() > 0);
- }
if (ite->second->ack_eliciting) {
++this->_ack_eliciting_outstanding;
ink_assert(this->_ack_eliciting_outstanding.load() > 0);
}
+ if (ite->second->in_flight) {
+ ++this->_num_packets_in_flight[index];
+ }
}
}
-void
-QUICLossDetector::_remove_from_sent_packet_list(QUICPacketNumber packet_number, QUICPacketNumberSpace pn_space)
-{
- SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread());
-
- auto ite = this->_sent_packets[static_cast<int>(pn_space)].find(packet_number);
- this->_decrement_outstanding_counters(ite, pn_space);
- this->_sent_packets[static_cast<int>(pn_space)].erase(packet_number);
-}
-
-std::map<QUICPacketNumber, QUICPacketInfoUPtr>::iterator
-QUICLossDetector::_remove_from_sent_packet_list(std::map<QUICPacketNumber, QUICPacketInfoUPtr>::iterator it,
+std::pair<QUICSentPacketInfoUPtr, std::map<QUICPacketNumber, QUICSentPacketInfoUPtr>::iterator>
+QUICLossDetector::_remove_from_sent_packet_list(std::map<QUICPacketNumber, QUICSentPacketInfoUPtr>::iterator it,
QUICPacketNumberSpace pn_space)
{
SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread());
- this->_decrement_outstanding_counters(it, pn_space);
- return this->_sent_packets[static_cast<int>(pn_space)].erase(it);
+ this->_decrement_counters(it, pn_space);
+ auto pi = std::move(it->second);
+ return {std::move(pi), this->_sent_packets[static_cast<int>(pn_space)].erase(it)};
}
void
-QUICLossDetector::_decrement_outstanding_counters(std::map<QUICPacketNumber, QUICPacketInfoUPtr>::iterator it,
- QUICPacketNumberSpace pn_space)
+QUICLossDetector::_decrement_counters(std::map<QUICPacketNumber, QUICSentPacketInfoUPtr>::iterator it,
+ QUICPacketNumberSpace pn_space)
{
if (it != this->_sent_packets[static_cast<int>(pn_space)].end()) {
- // Decrement counters
- if (it->second->is_crypto_packet) {
- ink_assert(this->_crypto_outstanding.load() > 0);
- --this->_crypto_outstanding;
- }
if (it->second->ack_eliciting) {
ink_assert(this->_ack_eliciting_outstanding.load() > 0);
--this->_ack_eliciting_outstanding;
}
+ --this->_num_packets_in_flight[static_cast<int>(pn_space)];
}
}
@@ -658,10 +720,11 @@ QUICRTTMeasure::update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay)
{
this->_latest_rtt = latest_rtt;
- if (this->_smoothed_rtt == 0) {
- this->_min_rtt = 0;
- this->_smoothed_rtt = this->_latest_rtt;
- this->_rttvar = this->_latest_rtt / 2;
+ if (this->_is_first_sample) {
+ this->_min_rtt = this->_latest_rtt;
+ this->_smoothed_rtt = this->_latest_rtt;
+ this->_rttvar = this->_latest_rtt / 2;
+ this->_is_first_sample = false;
return;
}
@@ -698,32 +761,16 @@ QUICRTTMeasure::congestion_period(uint32_t threshold) const
return pto * threshold;
}
-ink_hrtime
-QUICRTTMeasure::handshake_retransmit_timeout() const
-{
- // Handshake retransmission alarm.
- ink_hrtime timeout = 0;
- if (this->_smoothed_rtt == 0) {
- timeout = 2 * this->_k_initial_rtt;
- } else {
- timeout = 2 * this->_smoothed_rtt;
- }
- timeout = std::max(timeout, this->_k_granularity);
- timeout = timeout * (1 << this->_crypto_count);
-
- return timeout;
-}
-
void
-QUICRTTMeasure::set_crypto_count(uint32_t count)
+QUICRTTMeasure::set_pto_count(uint32_t count)
{
- this->_crypto_count = count;
+ this->_pto_count = count;
}
void
-QUICRTTMeasure::set_pto_count(uint32_t count)
+QUICRTTMeasure::set_max_ack_delay(ink_hrtime max_ack_delay)
{
- this->_pto_count = count;
+ this->_max_ack_delay = max_ack_delay;
}
ink_hrtime
@@ -739,15 +786,15 @@ QUICRTTMeasure::latest_rtt() const
}
uint32_t
-QUICRTTMeasure::crypto_count() const
+QUICRTTMeasure::pto_count() const
{
- return this->_crypto_count;
+ return this->_pto_count;
}
-uint32_t
-QUICRTTMeasure::pto_count() const
+ink_hrtime
+QUICRTTMeasure::max_ack_delay() const
{
- return this->_pto_count;
+ return this->_max_ack_delay;
}
ink_hrtime
@@ -759,10 +806,10 @@ QUICRTTMeasure::k_granularity() const
void
QUICRTTMeasure::reset()
{
- this->_crypto_count = 0;
+ // A.4. Initialization
this->_pto_count = 0;
- this->_smoothed_rtt = 0;
- this->_rttvar = 0;
- this->_min_rtt = 0;
this->_latest_rtt = 0;
+ this->_smoothed_rtt = this->_k_initial_rtt;
+ this->_rttvar = this->_k_initial_rtt / 2.0;
+ this->_min_rtt = 0;
}
diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h
index 891556e..5ed1c22 100644
--- a/iocore/net/quic/QUICLossDetector.h
+++ b/iocore/net/quic/QUICLossDetector.h
@@ -44,70 +44,6 @@ class QUICPinger;
class QUICLossDetector;
class QUICRTTMeasure;
-using QUICPacketInfoUPtr = std::unique_ptr<QUICPacketInfo>;
-
-class QUICRTTProvider
-{
-public:
- virtual ink_hrtime smoothed_rtt() const = 0;
- virtual ink_hrtime rttvar() const = 0;
- virtual ink_hrtime latest_rtt() const = 0;
-
- virtual ink_hrtime congestion_period(uint32_t threshold) const = 0;
-};
-
-class QUICNewRenoCongestionController : public QUICCongestionController
-{
-public:
- QUICNewRenoCongestionController(QUICContext &context);
- virtual ~QUICNewRenoCongestionController() {}
- void on_packet_sent(size_t bytes_sent) override;
- void on_packet_acked(const QUICPacketInfo &acked_packet) override;
- virtual void on_packets_lost(const std::map<QUICPacketNumber, QUICPacketInfo *> &packets) override;
- void process_ecn(const QUICPacketInfo &acked_largest_packet, const QUICAckFrame::EcnSection *ecn_section) override;
- bool check_credit() const;
- uint32_t credit() const override;
- void reset() override;
- bool is_app_limited();
-
- // Debug
- uint32_t bytes_in_flight() const override;
- uint32_t congestion_window() const override;
- uint32_t current_ssthresh() const override;
-
- void add_extra_credit() override;
-
-private:
- Ptr<ProxyMutex> _cc_mutex;
-
- void _congestion_event(ink_hrtime sent_time);
- bool _in_persistent_congestion(const std::map<QUICPacketNumber, QUICPacketInfo *> &lost_packets,
- QUICPacketInfo *largest_lost_packet);
- bool _in_window_lost(const std::map<QUICPacketNumber, QUICPacketInfo *> &lost_packets, QUICPacketInfo *largest_lost_packet,
- ink_hrtime period) const;
-
- uint32_t _extra_packets_count = 0;
-
- // [draft-17 recovery] 7.9.1. Constants of interest
- // Values will be loaded from records.config via QUICConfig at constructor
- uint32_t _k_max_datagram_size = 0;
- uint32_t _k_initial_window = 0;
- uint32_t _k_minimum_window = 0;
- float _k_loss_reduction_factor = 0.0;
- uint32_t _k_persistent_congestion_threshold = 3;
-
- // [draft-17 recovery] 7.9.2. Variables of interest
- uint32_t _ecn_ce_counter = 0;
- uint32_t _bytes_in_flight = 0;
- uint32_t _congestion_window = 0;
- ink_hrtime _congestion_recovery_start_time = 0;
- uint32_t _ssthresh = UINT32_MAX;
-
- bool _in_congestion_recovery(ink_hrtime sent_time) const;
-
- QUICContext &_context;
-};
-
class QUICLossDetector : public Continuation, public QUICFrameHandler
{
public:
@@ -117,9 +53,15 @@ public:
int event_handler(int event, Event *edata);
+ // QUICFrameHandler interface
std::vector<QUICFrameType> interests() override;
virtual QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override;
- void on_packet_sent(QUICPacketInfoUPtr packet_info, bool in_flight = true);
+
+ void on_packet_sent(QUICSentPacketInfoUPtr packet_info, bool in_flight = true);
+ void on_datagram_received();
+ // OnPacketNumberSpaceDiscarded is on Congestion Control section but having it here makes more sense because most processes are
+ // for LD.
+ void on_packet_number_space_discarded(QUICPacketNumberSpace pn_space);
QUICPacketNumber largest_acked_packet_number(QUICPacketNumberSpace pn_space) const;
void update_ack_delay_exponent(uint8_t ack_delay_exponent);
void reset();
@@ -129,29 +71,32 @@ private:
uint8_t _ack_delay_exponent = 3;
- // [draft-17 recovery] 6.4.1. Constants of interest
+ // Recovery A.2. Constants of Interest
// Values will be loaded from records.config via QUICConfig at constructor
uint32_t _k_packet_threshold = 0;
float _k_time_threshold = 0.0;
+ // kGranularity, kInitialRtt are defined in QUICRTTMeasure
+ QUICRTTMeasure *_rtt_measure = nullptr;
+ // kPacketNumberSpace is defined as QUICPacketNumberSpace on QUICTypes.h
- // [draft-11 recovery] 3.5.2. Variables of interest
+ // Recovery A.3. Variables of interest
// Keep the order as the same as the spec so that we can see the difference easily.
- Action *_loss_detection_timer = nullptr;
- ink_hrtime _time_of_last_sent_ack_eliciting_packet = 0;
- ink_hrtime _time_of_last_sent_crypto_packet = 0;
- ink_hrtime _loss_time[kPacketNumberSpace] = {0};
- QUICPacketNumber _largest_acked_packet[kPacketNumberSpace] = {0};
- std::map<QUICPacketNumber, QUICPacketInfoUPtr> _sent_packets[kPacketNumberSpace];
+ // latest_rtt, smoothed_rtt, rttvar, min_rtt and max_ack_delay are defined in QUICRttMeasure
+ Action *_loss_detection_timer = nullptr;
+ // pto_count is defined in QUICRttMeasure
+ ink_hrtime _time_of_last_ack_eliciting_packet[QUIC_N_PACKET_SPACES] = {0};
+ QUICPacketNumber _largest_acked_packet[QUIC_N_PACKET_SPACES] = {0};
+ ink_hrtime _loss_time[QUIC_N_PACKET_SPACES] = {0};
+ std::map<QUICPacketNumber, QUICSentPacketInfoUPtr> _sent_packets[QUIC_N_PACKET_SPACES];
// These are not defined on the spec but expected to be count
// These counter have to be updated when inserting / erasing packets from _sent_packets with following functions.
- std::atomic<uint32_t> _crypto_outstanding;
std::atomic<uint32_t> _ack_eliciting_outstanding;
- void _add_to_sent_packet_list(QUICPacketNumber packet_number, std::unique_ptr<QUICPacketInfo> packet_info);
- void _remove_from_sent_packet_list(QUICPacketNumber packet_number, QUICPacketNumberSpace pn_space);
- std::map<QUICPacketNumber, QUICPacketInfoUPtr>::iterator _remove_from_sent_packet_list(
- std::map<QUICPacketNumber, QUICPacketInfoUPtr>::iterator it, QUICPacketNumberSpace pn_space);
- void _decrement_outstanding_counters(std::map<QUICPacketNumber, QUICPacketInfoUPtr>::iterator it, QUICPacketNumberSpace pn_space);
+ std::atomic<uint32_t> _num_packets_in_flight[QUIC_N_PACKET_SPACES];
+ void _add_to_sent_packet_list(QUICPacketNumber packet_number, std::unique_ptr<QUICSentPacketInfo> packet_info);
+ std::pair<QUICSentPacketInfoUPtr, std::map<QUICPacketNumber, QUICSentPacketInfoUPtr>::iterator> _remove_from_sent_packet_list(
+ std::map<QUICPacketNumber, QUICSentPacketInfoUPtr>::iterator it, QUICPacketNumberSpace pn_space);
+ void _decrement_counters(std::map<QUICPacketNumber, QUICSentPacketInfoUPtr>::iterator it, QUICPacketNumberSpace pn_space);
/*
* Because this alarm will be reset on every packet transmission, to reduce number of events,
@@ -160,27 +105,28 @@ private:
ink_hrtime _loss_detection_alarm_at = 0;
void _on_ack_received(const QUICAckFrame &ack_frame, QUICPacketNumberSpace pn_space);
- void _on_packet_acked(const QUICPacketInfo &acked_packet);
- void _detect_lost_packets(QUICPacketNumberSpace pn_space);
+ void _on_packet_acked(const QUICSentPacketInfo &acked_packet);
+ std::map<QUICPacketNumber, QUICSentPacketInfoUPtr> _detect_and_remove_lost_packets(QUICPacketNumberSpace pn_space);
void _set_loss_detection_timer();
void _on_loss_detection_timeout();
- void _retransmit_lost_packet(const QUICPacketInfo &packet_info);
+ void _retransmit_lost_packet(const QUICSentPacketInfo &packet_info);
- ink_hrtime _get_earliest_loss_time(QUICPacketNumberSpace &pn_space);
+ ink_hrtime _get_loss_time_and_space(QUICPacketNumberSpace &space);
+ ink_hrtime _get_pto_time_and_space(QUICPacketNumberSpace &space);
+ bool _peer_completed_address_validation() const;
- std::vector<QUICPacketInfo *> _determine_newly_acked_packets(const QUICAckFrame &ack_frame, int pn_space);
- bool _include_ack_eliciting(const std::vector<QUICPacketInfo *> &acked_packets, int index) const;
+ std::vector<QUICSentPacketInfoUPtr> _detect_and_remove_acked_packets(const QUICAckFrame &ack_frame,
+ QUICPacketNumberSpace pn_space);
+ bool _include_ack_eliciting(const std::vector<QUICSentPacketInfoUPtr> &acked_packets) const;
- void _retransmit_all_unacked_crypto_data();
- void _send_one_or_two_packet();
- void _send_one_handshake_packets();
- void _send_one_padded_packets();
+ void _send_one_or_two_ack_eliciting_packet(QUICPacketNumberSpace pn_space);
+ void _send_one_ack_eliciting_handshake_packet();
+ void _send_one_ack_eliciting_padded_initial_packet();
void _send_packet(QUICEncryptionLevel level, bool padded = false);
bool _is_client_without_one_rtt_key() const;
- QUICRTTMeasure *_rtt_measure = nullptr;
QUICPinger *_pinger = nullptr;
QUICPadder *_padder = nullptr;
QUICCongestionController *_cc = nullptr;
@@ -200,7 +146,6 @@ public:
void init(const QUICLDConfig &ld_config);
// period
- ink_hrtime handshake_retransmit_timeout() const;
ink_hrtime current_pto_period() const;
ink_hrtime congestion_period(uint32_t threshold) const override;
@@ -210,10 +155,10 @@ public:
ink_hrtime latest_rtt() const override;
uint32_t pto_count() const;
- uint32_t crypto_count() const;
+ ink_hrtime max_ack_delay() const;
- void set_crypto_count(uint32_t count);
void set_pto_count(uint32_t count);
+ void set_max_ack_delay(ink_hrtime max_ack_delay);
void update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay);
void reset();
@@ -221,19 +166,18 @@ public:
ink_hrtime k_granularity() const;
private:
- // related to rtt calculate
- uint32_t _crypto_count = 0;
- uint32_t _pto_count = 0;
- // FIXME should be set by transport parameters
- ink_hrtime _max_ack_delay = HRTIME_MSECONDS(25);
+ bool _is_first_sample = false;
- // rtt vars
+ // A.3. Variables of interest
ink_hrtime _latest_rtt = 0;
ink_hrtime _smoothed_rtt = 0;
ink_hrtime _rttvar = 0;
ink_hrtime _min_rtt = INT64_MAX;
+ // FIXME should be set by transport parameters
+ ink_hrtime _max_ack_delay = HRTIME_MSECONDS(25);
+ uint32_t _pto_count = 0;
- // config
+ // Recovery A.2. Constants of Interest
ink_hrtime _k_granularity = 0;
ink_hrtime _k_initial_rtt = HRTIME_MSECONDS(500);
};
diff --git a/iocore/net/quic/QUICNewRenoCongestionController.cc b/iocore/net/quic/QUICNewRenoCongestionController.cc
index 2658443..7745670 100644
--- a/iocore/net/quic/QUICNewRenoCongestionController.cc
+++ b/iocore/net/quic/QUICNewRenoCongestionController.cc
@@ -22,19 +22,26 @@
*/
#include <tscore/Diags.h>
-#include <QUICLossDetector.h>
+#include <QUICCongestionController.h>
+#include <QUICNewRenoCongestionController.h>
#define QUICCCDebug(fmt, ...) \
Debug("quic_cc", \
"[%s] " \
- "window: %" PRIu32 " bytes: %" PRIu32 " ssthresh: %" PRIu32 " extra: %" PRIu32 " " fmt, \
+ "window:%" PRIu32 " in-flight:%" PRIu32 " ssthresh:%" PRIu32 " extra:%" PRIu32 " " fmt, \
+ this->_context.connection_info()->cids().data(), this->_congestion_window, this->_bytes_in_flight, this->_ssthresh, \
+ this->_extra_packets_count, ##__VA_ARGS__)
+#define QUICCCVDebug(fmt, ...) \
+ Debug("v_quic_cc", \
+ "[%s] " \
+ "window:%" PRIu32 " in-flight:%" PRIu32 " ssthresh:%" PRIu32 " extra:%" PRIu32 " " fmt, \
this->_context.connection_info()->cids().data(), this->_congestion_window, this->_bytes_in_flight, this->_ssthresh, \
this->_extra_packets_count, ##__VA_ARGS__)
#define QUICCCError(fmt, ...) \
Error("quic_cc", \
"[%s] " \
- "window: %" PRIu32 " bytes: %" PRIu32 " ssthresh: %" PRIu32 " extra %" PRIu32 " " fmt, \
+ "window:%" PRIu32 " in-flight:%" PRIu32 " ssthresh:%" PRIu32 " extra:%" PRIu32 " " fmt, \
this->_context.connection_info()->cids().data(), this->_congestion_window, this->_bytes_in_flight, this->_ssthresh, \
this->_extra_packets_count, ##__VA_ARGS__)
@@ -42,7 +49,6 @@ QUICNewRenoCongestionController::QUICNewRenoCongestionController(QUICContext &co
: _cc_mutex(new_ProxyMutex()), _context(context)
{
auto &cc_config = context.cc_config();
- this->_k_max_datagram_size = cc_config.max_datagram_size();
this->_k_initial_window = cc_config.initial_window();
this->_k_minimum_window = cc_config.minimum_window();
this->_k_loss_reduction_factor = cc_config.loss_reduction_factor();
@@ -69,46 +75,42 @@ QUICNewRenoCongestionController::_in_congestion_recovery(ink_hrtime sent_time) c
}
bool
-QUICNewRenoCongestionController::is_app_limited()
+QUICNewRenoCongestionController::_is_app_or_flow_control_limited()
{
// FIXME : don't known how does app worked here
return false;
}
void
-QUICNewRenoCongestionController::on_packet_acked(const QUICPacketInfo &acked_packet)
+QUICNewRenoCongestionController::_maybe_send_one_packet()
{
- // Remove from bytes_in_flight.
- SCOPED_MUTEX_LOCK(lock, this->_cc_mutex, this_ethread());
- this->_bytes_in_flight -= acked_packet.sent_bytes;
- if (this->_in_congestion_recovery(acked_packet.time_sent)) {
- // Do not increase congestion window in recovery period.
- return;
- }
+ // TODO Implement _maybe_send_one_packet
+}
- if (this->is_app_limited()) {
- // Do not increase congestion_window if application
- // limited.
- return;
- }
+bool
+QUICNewRenoCongestionController::_are_all_packets_lost(const std::map<QUICPacketNumber, QUICSentPacketInfoUPtr> &lost_packets,
+ const QUICSentPacketInfoUPtr &largest_lost_packet, ink_hrtime period) const
+{
+ // check whether packets are continuous. return true if all continuous packets are in period
+ QUICPacketNumber next_expected = UINT64_MAX;
+ for (auto &it : lost_packets) {
+ if (it.second->time_sent >= largest_lost_packet->time_sent - period) {
+ if (next_expected == UINT64_MAX) {
+ next_expected = it.second->packet_number + 1;
+ continue;
+ }
- if (this->_congestion_window < this->_ssthresh) {
- // Slow start.
- this->_context.trigger(QUICContext::CallbackEvent::CONGESTION_STATE_CHANGED, QUICCongestionController::State::SLOW_START);
- this->_congestion_window += acked_packet.sent_bytes;
- QUICCCDebug("slow start window changed");
- } else {
- // Congestion avoidance.
- this->_context.trigger(QUICContext::CallbackEvent::CONGESTION_STATE_CHANGED,
- QUICCongestionController::State::CONGESTION_AVOIDANCE);
- this->_congestion_window += this->_k_max_datagram_size * acked_packet.sent_bytes / this->_congestion_window;
- QUICCCDebug("Congestion avoidance window changed");
+ if (next_expected != it.second->packet_number) {
+ return false;
+ }
+
+ next_expected = it.second->packet_number + 1;
+ }
}
+
+ return next_expected == UINT64_MAX ? false : true;
}
-// additional code
-// the original one is:
-// CongestionEvent(sent_time):
void
QUICNewRenoCongestionController::_congestion_event(ink_hrtime sent_time)
{
@@ -122,54 +124,82 @@ QUICNewRenoCongestionController::_congestion_event(ink_hrtime sent_time)
this->_context.trigger(QUICContext::CallbackEvent::CONGESTION_STATE_CHANGED, QUICCongestionController::State::RECOVERY);
this->_context.trigger(QUICContext::CallbackEvent::METRICS_UPDATE, this->_congestion_window, this->_bytes_in_flight,
this->_ssthresh);
+ // A packet can be sent to speed up loss recovery.
+ this->_maybe_send_one_packet();
}
}
-// additional code
-// the original one is:
-// ProcessECN(ack):
void
-QUICNewRenoCongestionController::process_ecn(const QUICPacketInfo &acked_largest_packet,
- const QUICAckFrame::EcnSection *ecn_section)
+QUICNewRenoCongestionController::process_ecn(const QUICAckFrame &ack_frame, QUICPacketNumberSpace pn_space,
+ ink_hrtime largest_acked_time_sent)
{
// If the ECN-CE counter reported by the peer has increased,
// this could be a new congestion event.
- if (ecn_section->ecn_ce_count() > this->_ecn_ce_counter) {
- this->_ecn_ce_counter = ecn_section->ecn_ce_count();
+ if (ack_frame.ecn_section()->ecn_ce_count() > this->_ecn_ce_counters[static_cast<int>(pn_space)]) {
+ this->_ecn_ce_counters[static_cast<int>(pn_space)] = ack_frame.ecn_section()->ecn_ce_count();
// Start a new congestion event if the last acknowledged
// packet was sent after the start of the previous
// recovery epoch.
- this->_congestion_event(acked_largest_packet.time_sent);
+ this->_congestion_event(largest_acked_time_sent);
}
}
bool
-QUICNewRenoCongestionController::_in_persistent_congestion(const std::map<QUICPacketNumber, QUICPacketInfo *> &lost_packets,
- QUICPacketInfo *largest_lost_packet)
+QUICNewRenoCongestionController::_in_persistent_congestion(const std::map<QUICPacketNumber, QUICSentPacketInfoUPtr> &lost_packets,
+ const QUICSentPacketInfoUPtr &largest_lost_packet)
{
- ink_hrtime period = this->_context.rtt_provider()->congestion_period(this->_k_persistent_congestion_threshold);
- // Determine if all packets in the window before the
- // newest lost packet, including the edges, are marked
- // lost
- return this->_in_window_lost(lost_packets, largest_lost_packet, period);
+ ink_hrtime congestion_period = this->_context.rtt_provider()->congestion_period(this->_k_persistent_congestion_threshold);
+ // Determine if all packets in the time period before the
+ // largest newly lost packet, including the edges, are
+ // marked lost
+ return this->_are_all_packets_lost(lost_packets, largest_lost_packet, congestion_period);
+}
+
+void
+QUICNewRenoCongestionController::on_packets_acked(const std::vector<QUICSentPacketInfoUPtr> &packets)
+{
+ SCOPED_MUTEX_LOCK(lock, this->_cc_mutex, this_ethread());
+
+ for (auto &packet : packets) {
+ // Remove from bytes_in_flight.
+ this->_bytes_in_flight -= packet->sent_bytes;
+ if (this->_in_congestion_recovery(packet->time_sent)) {
+ // Do not increase congestion window in recovery period.
+ continue;
+ }
+ if (this->_is_app_or_flow_control_limited()) {
+ // Do not increase congestion_window if application
+ // limited or flow control limited.
+ continue;
+ }
+ if (this->_congestion_window < this->_ssthresh) {
+ // Slow start.
+ this->_context.trigger(QUICContext::CallbackEvent::CONGESTION_STATE_CHANGED, QUICCongestionController::State::SLOW_START);
+ this->_congestion_window += packet->sent_bytes;
+ QUICCCVDebug("slow start window changed");
+ continue;
+ }
+ // Congestion avoidance.
+ this->_context.trigger(QUICContext::CallbackEvent::CONGESTION_STATE_CHANGED,
+ QUICCongestionController::State::CONGESTION_AVOIDANCE);
+ this->_congestion_window += this->_max_datagram_size * static_cast<double>(packet->sent_bytes) / this->_congestion_window;
+ QUICCCVDebug("Congestion avoidance window changed");
+ }
}
// additional code
// the original one is:
// OnPacketsLost(lost_packets):
void
-QUICNewRenoCongestionController::on_packets_lost(const std::map<QUICPacketNumber, QUICPacketInfo *> &lost_packets)
+QUICNewRenoCongestionController::on_packets_lost(const std::map<QUICPacketNumber, QUICSentPacketInfoUPtr> &lost_packets)
{
- if (lost_packets.empty()) {
- return;
- }
-
SCOPED_MUTEX_LOCK(lock, this->_cc_mutex, this_ethread());
+
// Remove lost packets from bytes_in_flight.
for (auto &lost_packet : lost_packets) {
this->_bytes_in_flight -= lost_packet.second->sent_bytes;
}
- QUICPacketInfo *largest_lost_packet = lost_packets.rbegin()->second;
+ const auto &largest_lost_packet = lost_packets.rbegin()->second;
this->_congestion_event(largest_lost_packet->time_sent);
// Collapse congestion window if persistent congestion
@@ -178,8 +208,14 @@ QUICNewRenoCongestionController::on_packets_lost(const std::map<QUICPacketNumber
}
}
+void
+QUICNewRenoCongestionController::on_packet_number_space_discarded(size_t bytes_in_flight)
+{
+ this->_bytes_in_flight -= bytes_in_flight;
+}
+
bool
-QUICNewRenoCongestionController::check_credit() const
+QUICNewRenoCongestionController::_check_credit() const
{
if (this->_bytes_in_flight >= this->_congestion_window) {
QUICCCDebug("Congestion control pending");
@@ -195,7 +231,7 @@ QUICNewRenoCongestionController::credit() const
return UINT32_MAX;
}
- if (this->check_credit()) {
+ if (this->_check_credit()) {
return this->_congestion_window - this->_bytes_in_flight;
} else {
return 0;
@@ -226,34 +262,13 @@ QUICNewRenoCongestionController::reset()
{
SCOPED_MUTEX_LOCK(lock, this->_cc_mutex, this_ethread());
- this->_bytes_in_flight = 0;
this->_congestion_window = this->_k_initial_window;
+ this->_bytes_in_flight = 0;
this->_congestion_recovery_start_time = 0;
this->_ssthresh = UINT32_MAX;
-}
-
-bool
-QUICNewRenoCongestionController::_in_window_lost(const std::map<QUICPacketNumber, QUICPacketInfo *> &lost_packets,
- QUICPacketInfo *largest_lost_packet, ink_hrtime period) const
-{
- // check whether packets are continuous. return true if all continuous packets are in period
- QUICPacketNumber next_expected = UINT64_MAX;
- for (auto &it : lost_packets) {
- if (it.second->time_sent >= largest_lost_packet->time_sent - period) {
- if (next_expected == UINT64_MAX) {
- next_expected = it.second->packet_number + 1;
- continue;
- }
-
- if (next_expected != it.second->packet_number) {
- return false;
- }
-
- next_expected = it.second->packet_number + 1;
- }
+ for (int i = 0; i < QUIC_N_PACKET_SPACES; ++i) {
+ this->_ecn_ce_counters[i] = 0;
}
-
- return next_expected == UINT64_MAX ? false : true;
}
void
diff --git a/iocore/net/quic/QUICNewRenoCongestionController.h b/iocore/net/quic/QUICNewRenoCongestionController.h
new file mode 100644
index 0000000..43a870c
--- /dev/null
+++ b/iocore/net/quic/QUICNewRenoCongestionController.h
@@ -0,0 +1,81 @@
+/** @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 "QUICTypes.h"
+#include "QUICContext.h"
+#include "QUICCongestionController.h"
+
+class QUICNewRenoCongestionController : public QUICCongestionController
+{
+public:
+ QUICNewRenoCongestionController(QUICContext &context);
+ virtual ~QUICNewRenoCongestionController() {}
+
+ void on_packet_sent(size_t bytes_sent) override;
+ void on_packets_acked(const std::vector<QUICSentPacketInfoUPtr> &packets) override;
+ virtual void on_packets_lost(const std::map<QUICPacketNumber, QUICSentPacketInfoUPtr> &packets) override;
+ void on_packet_number_space_discarded(size_t bytes_in_flight) override;
+ void process_ecn(const QUICAckFrame &ack, QUICPacketNumberSpace pn_space, ink_hrtime largest_acked_packet_time_sent) override;
+ uint32_t credit() const override;
+ void reset() override;
+
+ // Debug
+ uint32_t bytes_in_flight() const override;
+ uint32_t congestion_window() const override;
+ uint32_t current_ssthresh() const override;
+
+ void add_extra_credit() override;
+
+private:
+ Ptr<ProxyMutex> _cc_mutex;
+ uint32_t _extra_packets_count = 0;
+ QUICContext &_context;
+ bool _check_credit() const;
+
+ // Appendix B. Congestion Control Pseudocode
+ bool _in_congestion_recovery(ink_hrtime sent_time) const;
+ void _congestion_event(ink_hrtime sent_time);
+ bool _in_persistent_congestion(const std::map<QUICPacketNumber, QUICSentPacketInfoUPtr> &lost_packets,
+ const QUICSentPacketInfoUPtr &largest_lost_packet);
+ bool _is_app_or_flow_control_limited();
+ void _maybe_send_one_packet();
+ bool _are_all_packets_lost(const std::map<QUICPacketNumber, QUICSentPacketInfoUPtr> &lost_packets,
+ const QUICSentPacketInfoUPtr &largest_lost_packet, ink_hrtime period) const;
+
+ // Recovery B.1. Constants of interest
+ // Values will be loaded from records.config via QUICConfig at constructor
+ uint32_t _k_initial_window = 0;
+ uint32_t _k_minimum_window = 0;
+ float _k_loss_reduction_factor = 0.0;
+ uint32_t _k_persistent_congestion_threshold = 0;
+
+ // B.2. Variables of interest
+ uint32_t _max_datagram_size = 0;
+ uint32_t _ecn_ce_counters[QUIC_N_PACKET_SPACES] = {0};
+ uint32_t _bytes_in_flight = 0;
+ uint32_t _congestion_window = 0;
+ ink_hrtime _congestion_recovery_start_time = 0;
+ uint32_t _ssthresh = UINT32_MAX;
+};
diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc
index 0bcf624..5f5707d 100644
--- a/iocore/net/quic/QUICPacket.cc
+++ b/iocore/net/quic/QUICPacket.cc
@@ -883,9 +883,14 @@ QUICStatelessResetPacketR::destination_cid() const
//
// QUICVersionNegotiationPacket
//
-QUICVersionNegotiationPacket::QUICVersionNegotiationPacket(QUICConnectionId dcid, QUICConnectionId scid,
- const QUICVersion versions[], int nversions)
- : QUICLongHeaderPacket(0, dcid, scid, false, false, false), _versions(versions), _nversions(nversions)
+
+QUICVersionNegotiationPacket::QUICVersionNegotiationPacket(const QUICConnectionId &dcid, const QUICConnectionId &scid,
+ const QUICVersion versions[], int nversions,
+ QUICVersion version_in_initial)
+ : QUICLongHeaderPacket(0, dcid, scid, false, false, false),
+ _versions(versions),
+ _nversions(nversions),
+ _version_in_initial(version_in_initial)
{
}
@@ -961,7 +966,11 @@ QUICVersionNegotiationPacket::payload_block() const
// [draft-18] 6.3. Using Reserved Versions
// To help ensure this, a server SHOULD include a reserved version (see Section 15) while generating a
// Version Negotiation packet.
- QUICTypeUtil::write_QUICVersion(QUIC_EXERCISE_VERSION, buf + written_len, &n);
+ QUICVersion exersice_version = QUIC_EXERCISE_VERSION1;
+ if (this->_version_in_initial == QUIC_EXERCISE_VERSION1) {
+ exersice_version = QUIC_EXERCISE_VERSION2;
+ }
+ QUICTypeUtil::write_QUICVersion(exersice_version, buf + written_len, &n);
written_len += n;
block->fill(written_len);
@@ -1736,7 +1745,7 @@ QUICRetryPacket::payload_block() const
block->fill(written_len);
// Retry Integrity Tag
- QUICRetryIntegrityTag::compute(buf + written_len, this->_token.original_dcid(), this->header_block(), block);
+ QUICRetryIntegrityTag::compute(buf + written_len, this->version(), this->_token.original_dcid(), this->header_block(), block);
written_len += QUICRetryIntegrityTag::LEN;
block->fill(QUICRetryIntegrityTag::LEN);
@@ -1838,7 +1847,7 @@ bool
QUICRetryPacketR::has_valid_tag(const QUICConnectionId &odcid) const
{
uint8_t tag_computed[QUICRetryIntegrityTag::LEN];
- QUICRetryIntegrityTag::compute(tag_computed, odcid, this->_header_block, this->_payload_block_without_tag);
+ QUICRetryIntegrityTag::compute(tag_computed, this->version(), odcid, this->_header_block, this->_payload_block_without_tag);
return memcmp(this->_integrity_tag, tag_computed, QUICRetryIntegrityTag::LEN) == 0;
}
diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h
index a62daa4..e9d0212 100644
--- a/iocore/net/quic/QUICPacket.h
+++ b/iocore/net/quic/QUICPacket.h
@@ -319,7 +319,8 @@ public:
/**
* For sending packet
*/
- QUICVersionNegotiationPacket(QUICConnectionId dcid, QUICConnectionId scid, const QUICVersion versions[], int nversions);
+ QUICVersionNegotiationPacket(const QUICConnectionId &dcid, const QUICConnectionId &scid, const QUICVersion versions[],
+ int nversions, QUICVersion version_in_initial);
QUICPacketType type() const override;
QUICVersion version() const override;
@@ -335,6 +336,7 @@ public:
private:
const QUICVersion *_versions;
int _nversions;
+ const QUICVersion _version_in_initial;
};
class QUICVersionNegotiationPacketR : public QUICLongHeaderPacketR
diff --git a/iocore/net/quic/QUICPacketFactory.cc b/iocore/net/quic/QUICPacketFactory.cc
index 436c683..2fcb1a2 100644
--- a/iocore/net/quic/QUICPacketFactory.cc
+++ b/iocore/net/quic/QUICPacketFactory.cc
@@ -197,10 +197,11 @@ QUICPacketFactory::create(uint8_t *packet_buf, UDPConnection *udp_con, IpEndpoin
}
QUICPacketUPtr
-QUICPacketFactory::create_version_negotiation_packet(QUICConnectionId dcid, QUICConnectionId scid)
+QUICPacketFactory::create_version_negotiation_packet(QUICConnectionId dcid, QUICConnectionId scid, QUICVersion version_in_initial)
{
- return QUICPacketUPtr(new QUICVersionNegotiationPacket(dcid, scid, QUIC_SUPPORTED_VERSIONS, countof(QUIC_SUPPORTED_VERSIONS)),
- &QUICPacketDeleter::delete_packet_new);
+ return QUICPacketUPtr(
+ new QUICVersionNegotiationPacket(dcid, scid, QUIC_SUPPORTED_VERSIONS, countof(QUIC_SUPPORTED_VERSIONS), version_in_initial),
+ &QUICPacketDeleter::delete_packet_new);
}
QUICPacketUPtr
@@ -228,10 +229,10 @@ QUICPacketFactory::create_initial_packet(uint8_t *packet_buf, QUICConnectionId d
}
QUICPacketUPtr
-QUICPacketFactory::create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICRetryToken &token)
+QUICPacketFactory::create_retry_packet(QUICVersion version, QUICConnectionId destination_cid, QUICConnectionId source_cid,
+ QUICRetryToken &token)
{
- return QUICPacketUPtr(new QUICRetryPacket(QUIC_SUPPORTED_VERSIONS[0], destination_cid, source_cid, token),
- &QUICPacketDeleter::delete_packet_new);
+ return QUICPacketUPtr(new QUICRetryPacket(version, destination_cid, source_cid, token), &QUICPacketDeleter::delete_packet_new);
}
QUICPacketUPtr
@@ -329,7 +330,7 @@ QUICPacketFactory::is_ready_to_create_protected_packet()
void
QUICPacketFactory::reset()
{
- for (auto i = 0; i < kPacketNumberSpace; i++) {
+ for (auto i = 0; i < QUIC_N_PACKET_SPACES; i++) {
this->_packet_number_generator[i].reset();
}
}
diff --git a/iocore/net/quic/QUICPacketFactory.h b/iocore/net/quic/QUICPacketFactory.h
index d5316ce..2d59de6 100644
--- a/iocore/net/quic/QUICPacketFactory.h
+++ b/iocore/net/quic/QUICPacketFactory.h
@@ -44,9 +44,11 @@ class QUICPacketFactory
{
public:
static QUICPacketUPtr create_null_packet();
- static QUICPacketUPtr create_version_negotiation_packet(QUICConnectionId dcid, QUICConnectionId scid);
+ static QUICPacketUPtr create_version_negotiation_packet(QUICConnectionId dcid, QUICConnectionId scid,
+ QUICVersion version_in_version);
static QUICPacketUPtr create_stateless_reset_packet(QUICStatelessResetToken stateless_reset_token, size_t maximum_size);
- static QUICPacketUPtr create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICRetryToken &token);
+ static QUICPacketUPtr create_retry_packet(QUICVersion version, QUICConnectionId destination_cid, QUICConnectionId source_cid,
+ QUICRetryToken &token);
QUICPacketFactory(const QUICPacketProtectionKeyInfo &pp_key_info) : _pp_key_info(pp_key_info), _pp_protector(pp_key_info) {}
diff --git a/iocore/net/quic/QUICRetryIntegrityTag.cc b/iocore/net/quic/QUICRetryIntegrityTag.cc
index c528656..117dff6 100644
--- a/iocore/net/quic/QUICRetryIntegrityTag.cc
+++ b/iocore/net/quic/QUICRetryIntegrityTag.cc
@@ -24,7 +24,8 @@
#include "QUICRetryIntegrityTag.h"
bool
-QUICRetryIntegrityTag::compute(uint8_t *out, QUICConnectionId odcid, Ptr<IOBufferBlock> header, Ptr<IOBufferBlock> payload)
+QUICRetryIntegrityTag::compute(uint8_t *out, QUICVersion version, QUICConnectionId odcid, Ptr<IOBufferBlock> header,
+ Ptr<IOBufferBlock> payload)
{
EVP_CIPHER_CTX *aead_ctx;
@@ -37,7 +38,23 @@ QUICRetryIntegrityTag::compute(uint8_t *out, QUICConnectionId odcid, Ptr<IOBuffe
if (!EVP_CIPHER_CTX_ctrl(aead_ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, nullptr)) {
return false;
}
- if (!EVP_EncryptInit_ex(aead_ctx, nullptr, nullptr, KEY_FOR_RETRY_INTEGRITY_TAG, NONCE_FOR_RETRY_INTEGRITY_TAG)) {
+ const uint8_t *key;
+ const uint8_t *nonce;
+ switch (version) {
+ case 0xff00001d: // Draft-29
+ key = KEY_FOR_RETRY_INTEGRITY_TAG;
+ nonce = NONCE_FOR_RETRY_INTEGRITY_TAG;
+ break;
+ case 0xff00001b: // Draft-27
+ key = KEY_FOR_RETRY_INTEGRITY_TAG_D27;
+ nonce = NONCE_FOR_RETRY_INTEGRITY_TAG_D27;
+ break;
+ default:
+ key = KEY_FOR_RETRY_INTEGRITY_TAG;
+ nonce = NONCE_FOR_RETRY_INTEGRITY_TAG;
+ break;
+ }
+ if (!EVP_EncryptInit_ex(aead_ctx, nullptr, nullptr, key, nonce)) {
return false;
}
diff --git a/iocore/net/quic/QUICRetryIntegrityTag.h b/iocore/net/quic/QUICRetryIntegrityTag.h
index 3ac9498..081bd59 100644
--- a/iocore/net/quic/QUICRetryIntegrityTag.h
+++ b/iocore/net/quic/QUICRetryIntegrityTag.h
@@ -29,11 +29,17 @@ class QUICRetryIntegrityTag
{
public:
static constexpr int LEN = 16;
- static bool compute(uint8_t *out, QUICConnectionId odcid, Ptr<IOBufferBlock> header, Ptr<IOBufferBlock> payload);
+ static bool compute(uint8_t *out, QUICVersion version, QUICConnectionId odcid, Ptr<IOBufferBlock> header,
+ Ptr<IOBufferBlock> payload);
private:
- static constexpr uint8_t KEY_FOR_RETRY_INTEGRITY_TAG[] = {0x4d, 0x32, 0xec, 0xdb, 0x2a, 0x21, 0x33, 0xc8,
- 0x41, 0xe4, 0x04, 0x3d, 0xf2, 0x7d, 0x44, 0x30};
- static constexpr uint8_t NONCE_FOR_RETRY_INTEGRITY_TAG[] = {0x4d, 0x16, 0x11, 0xd0, 0x55, 0x13,
- 0xa5, 0x52, 0xc5, 0x87, 0xd5, 0x75};
+ static constexpr uint8_t KEY_FOR_RETRY_INTEGRITY_TAG[] = {0xcc, 0xce, 0x18, 0x7e, 0xd0, 0x9a, 0x09, 0xd0,
+ 0x57, 0x28, 0x15, 0x5a, 0x6c, 0xb9, 0x6b, 0xe1};
+ static constexpr uint8_t NONCE_FOR_RETRY_INTEGRITY_TAG[] = {0xe5, 0x49, 0x30, 0xf9, 0x7f, 0x21,
+ 0x36, 0xf0, 0x53, 0x0a, 0x8c, 0x1c};
+ // For draft 27
+ static constexpr uint8_t KEY_FOR_RETRY_INTEGRITY_TAG_D27[] = {0x4d, 0x32, 0xec, 0xdb, 0x2a, 0x21, 0x33, 0xc8,
+ 0x41, 0xe4, 0x04, 0x3d, 0xf2, 0x7d, 0x44, 0x30};
+ static constexpr uint8_t NONCE_FOR_RETRY_INTEGRITY_TAG_D27[] = {0x4d, 0x16, 0x11, 0xd0, 0x55, 0x13,
+ 0xa5, 0x52, 0xc5, 0x87, 0xd5, 0x75};
};
diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h
index bff660a..afeb03c 100644
--- a/iocore/net/quic/QUICStream.h
+++ b/iocore/net/quic/QUICStream.h
@@ -130,5 +130,8 @@ protected:
#define QUICStreamFCDebug(fmt, ...) \
Debug("quic_flow_ctrl", "[%s] [%" PRIu64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \
QUICDebugNames::stream_state(this->_state.get()), ##__VA_ARGS__)
+#define QUICVStreamFCDebug(fmt, ...) \
+ Debug("v_quic_flow_ctrl", "[%s] [%" PRIu64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \
+ QUICDebugNames::stream_state(this->_state.get()), ##__VA_ARGS__)
extern const uint32_t MAX_STREAM_FRAME_OVERHEAD;
diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc
index 4764ea1..a618e3a 100644
--- a/iocore/net/quic/QUICTLS.cc
+++ b/iocore/net/quic/QUICTLS.cc
@@ -165,7 +165,7 @@ QUICTLS::is_ready_to_derive() const
}
int
-QUICTLS::initialize_key_materials(QUICConnectionId cid)
+QUICTLS::initialize_key_materials(QUICConnectionId cid, QUICVersion version)
{
this->_pp_key_info.set_cipher_initial(EVP_aes_128_gcm());
this->_pp_key_info.set_cipher_for_hp_initial(EVP_aes_128_ecb());
@@ -217,8 +217,8 @@ QUICTLS::initialize_key_materials(QUICConnectionId cid)
server_iv_len = this->_pp_key_info.decryption_iv_len(QUICKeyPhase::INITIAL);
}
- this->_keygen_for_client.generate(client_key_for_hp, client_key, client_iv, client_iv_len, cid);
- this->_keygen_for_server.generate(server_key_for_hp, server_key, server_iv, server_iv_len, cid);
+ this->_keygen_for_client.generate(version, client_key_for_hp, client_key, client_iv, client_iv_len, cid);
+ this->_keygen_for_server.generate(version, server_key_for_hp, server_key, server_iv, server_iv_len, cid);
this->_pp_key_info.set_decryption_key_available(QUICKeyPhase::INITIAL);
this->_pp_key_info.set_encryption_key_available(QUICKeyPhase::INITIAL);
diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h
index e60d920..938e1e2 100644
--- a/iocore/net/quic/QUICTLS.h
+++ b/iocore/net/quic/QUICTLS.h
@@ -71,7 +71,7 @@ public:
void reset() override;
bool is_handshake_finished() const override;
bool is_ready_to_derive() const override;
- int initialize_key_materials(QUICConnectionId cid) override;
+ int initialize_key_materials(QUICConnectionId cid, QUICVersion version) override;
void update_negotiated_cipher();
void update_key_materials_for_read(QUICEncryptionLevel level, const uint8_t *secret, size_t secret_len);
void update_key_materials_for_write(QUICEncryptionLevel level, const uint8_t *secret, size_t secret_len);
diff --git a/iocore/net/quic/QUICTLS_boringssl.cc b/iocore/net/quic/QUICTLS_boringssl.cc
index 46f70f0..01aabfa 100644
--- a/iocore/net/quic/QUICTLS_boringssl.cc
+++ b/iocore/net/quic/QUICTLS_boringssl.cc
@@ -30,6 +30,7 @@
#include <openssl/aead.h>
#include "QUICGlobals.h"
+#include "QUICConnection.h"
#include "QUICPacketProtectionKeyInfo.h"
static constexpr char tag[] = "quic_tls";
@@ -80,10 +81,13 @@ set_write_secret(SSL *ssl, enum ssl_encryption_level_t level, const SSL_CIPHER *
const uint8_t *tp_buf;
size_t tp_buf_len;
SSL_get_peer_quic_transport_params(ssl, &tp_buf, &tp_buf_len);
+ const QUICConnection *qc = static_cast<const QUICConnection *>(SSL_get_ex_data(ssl, QUIC::ssl_quic_qc_index));
+ QUICVersion version = qc->negotiated_version();
if (SSL_is_server(ssl)) {
- qtls->set_remote_transport_parameters(std::make_shared<QUICTransportParametersInClientHello>(tp_buf, tp_buf_len));
+ qtls->set_remote_transport_parameters(std::make_shared<QUICTransportParametersInClientHello>(tp_buf, tp_buf_len, version));
} else {
- qtls->set_remote_transport_parameters(std::make_shared<QUICTransportParametersInEncryptedExtensions>(tp_buf, tp_buf_len));
+ qtls->set_remote_transport_parameters(
+ std::make_shared<QUICTransportParametersInEncryptedExtensions>(tp_buf, tp_buf_len, version));
}
}
@@ -111,10 +115,13 @@ set_encryption_secrets(SSL *ssl, enum ssl_encryption_level_t level, const uint8_
const uint8_t *tp_buf;
size_t tp_buf_len;
SSL_get_peer_quic_transport_params(ssl, &tp_buf, &tp_buf_len);
+ const QUICConnection *qc = static_cast<const QUICConnection *>(SSL_get_ex_data(ssl, QUIC::ssl_quic_qc_index));
+ QUICVersion version = qc->negotiated_version();
if (SSL_is_server(ssl)) {
- qtls->set_remote_transport_parameters(std::make_shared<QUICTransportParametersInClientHello>(tp_buf, tp_buf_len));
+ qtls->set_remote_transport_parameters(std::make_shared<QUICTransportParametersInClientHello>(tp_buf, tp_buf_len, version));
} else {
- qtls->set_remote_transport_parameters(std::make_shared<QUICTransportParametersInEncryptedExtensions>(tp_buf, tp_buf_len));
+ qtls->set_remote_transport_parameters(
+ std::make_shared<QUICTransportParametersInEncryptedExtensions>(tp_buf, tp_buf_len, version));
}
}
diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc
index 28dfbf1..c34598d 100644
--- a/iocore/net/quic/QUICTLS_openssl.cc
+++ b/iocore/net/quic/QUICTLS_openssl.cc
@@ -29,6 +29,7 @@
#include <openssl/evp.h>
#include "QUICGlobals.h"
+#include "QUICConnection.h"
#include "QUICPacketProtectionKeyInfo.h"
static constexpr char tag[] = "quic_tls";
@@ -71,10 +72,13 @@ set_encryption_secrets(SSL *ssl, enum ssl_encryption_level_t level, const uint8_
const uint8_t *tp_buf;
size_t tp_buf_len;
SSL_get_peer_quic_transport_params(ssl, &tp_buf, &tp_buf_len);
+ const QUICConnection *qc = static_cast<const QUICConnection *>(SSL_get_ex_data(ssl, QUIC::ssl_quic_qc_index));
+ QUICVersion version = qc->negotiated_version();
if (SSL_is_server(ssl)) {
- qtls->set_remote_transport_parameters(std::make_shared<QUICTransportParametersInClientHello>(tp_buf, tp_buf_len));
+ qtls->set_remote_transport_parameters(std::make_shared<QUICTransportParametersInClientHello>(tp_buf, tp_buf_len, version));
} else {
- qtls->set_remote_transport_parameters(std::make_shared<QUICTransportParametersInEncryptedExtensions>(tp_buf, tp_buf_len));
+ qtls->set_remote_transport_parameters(
+ std::make_shared<QUICTransportParametersInEncryptedExtensions>(tp_buf, tp_buf_len, version));
}
}
diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc
index cead970..c113458 100644
--- a/iocore/net/quic/QUICTransportParameters.cc
+++ b/iocore/net/quic/QUICTransportParameters.cc
@@ -35,9 +35,9 @@ static constexpr char tag[] = "quic_handshake";
static constexpr int TRANSPORT_PARAMETERS_MAXIMUM_SIZE = 65535;
-static constexpr uint32_t TP_ERROR_LENGTH = 0x010000;
-static constexpr uint32_t TP_ERROR_VALUE = 0x020000;
-// static constexpr uint32_t TP_ERROR_MUST_EXIST = 0x030000;
+static constexpr uint32_t TP_ERROR_LENGTH = 0x010000;
+static constexpr uint32_t TP_ERROR_VALUE = 0x020000;
+static constexpr uint32_t TP_ERROR_MUST_EXIST = 0x030000;
static constexpr uint32_t TP_ERROR_MUST_NOT_EXIST = 0x040000;
QUICTransportParameters::Value::Value(const uint8_t *data, uint16_t len) : _len(len)
@@ -70,6 +70,14 @@ QUICTransportParameters::Value::len() const
return this->_len;
}
+QUICTransportParameters::QUICTransportParameters(const uint8_t *buf, size_t len, QUICVersion version)
+{
+ this->_load(buf, len, version);
+ if (is_debug_tag_set(tag)) {
+ this->_print();
+ }
+}
+
QUICTransportParameters::~QUICTransportParameters()
{
for (auto p : this->_parameters) {
@@ -78,7 +86,7 @@ QUICTransportParameters::~QUICTransportParameters()
}
void
-QUICTransportParameters::_load(const uint8_t *buf, size_t len)
+QUICTransportParameters::_load(const uint8_t *buf, size_t len, QUICVersion version)
{
bool has_error = false;
const uint8_t *p = buf;
@@ -130,7 +138,7 @@ QUICTransportParameters::_load(const uint8_t *buf, size_t len)
}
// Validate parameters
- int res = this->_validate_parameters();
+ int res = this->_validate_parameters(version);
if (res < 0) {
Debug(tag, "Transport parameter is not valid (err=%d)", res);
this->_valid = false;
@@ -140,7 +148,7 @@ QUICTransportParameters::_load(const uint8_t *buf, size_t len)
}
int
-QUICTransportParameters::_validate_parameters() const
+QUICTransportParameters::_validate_parameters(QUICVersion version) const
{
decltype(this->_parameters)::const_iterator ite;
@@ -159,9 +167,9 @@ QUICTransportParameters::_validate_parameters() const
if ((ite = this->_parameters.find(QUICTransportParameterId::MAX_IDLE_TIMEOUT)) != this->_parameters.end()) {
}
- if ((ite = this->_parameters.find(QUICTransportParameterId::MAX_PACKET_SIZE)) != this->_parameters.end()) {
+ if ((ite = this->_parameters.find(QUICTransportParameterId::MAX_UDP_PAYLOAD_SIZE)) != this->_parameters.end()) {
if (QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) < 1200) {
- return -(TP_ERROR_VALUE | QUICTransportParameterId::MAX_PACKET_SIZE);
+ return -(TP_ERROR_VALUE | QUICTransportParameterId::MAX_UDP_PAYLOAD_SIZE);
}
}
@@ -262,6 +270,10 @@ QUICTransportParameters::store(uint8_t *buf, uint16_t *len) const
}
*len = (p - buf);
+
+ if (is_debug_tag_set(tag)) {
+ this->_print();
+ }
}
void
@@ -301,12 +313,9 @@ QUICTransportParameters::_print() const
// QUICTransportParametersInClientHello
//
-QUICTransportParametersInClientHello::QUICTransportParametersInClientHello(const uint8_t *buf, size_t len)
+QUICTransportParametersInClientHello::QUICTransportParametersInClientHello(const uint8_t *buf, size_t len, QUICVersion version)
+ : QUICTransportParameters(buf, len, version)
{
- this->_load(buf, len);
- if (is_debug_tag_set(tag)) {
- this->_print();
- }
}
std::ptrdiff_t
@@ -316,9 +325,9 @@ QUICTransportParametersInClientHello::_parameters_offset(const uint8_t *) const
}
int
-QUICTransportParametersInClientHello::_validate_parameters() const
+QUICTransportParametersInClientHello::_validate_parameters(QUICVersion version) const
{
- int res = QUICTransportParameters::_validate_parameters();
+ int res = QUICTransportParameters::_validate_parameters(version);
if (res < 0) {
return res;
}
@@ -326,14 +335,22 @@ QUICTransportParametersInClientHello::_validate_parameters() const
decltype(this->_parameters)::const_iterator ite;
// MUST NOTs
- if ((ite = this->_parameters.find(QUICTransportParameterId::STATELESS_RESET_TOKEN)) != this->_parameters.end()) {
- return -(TP_ERROR_MUST_NOT_EXIST | QUICTransportParameterId::STATELESS_RESET_TOKEN);
+ if ((ite = this->_parameters.find(QUICTransportParameterId::ORIGINAL_DESTINATION_CONNECTION_ID)) != this->_parameters.end()) {
+ return -(TP_ERROR_MUST_NOT_EXIST | QUICTransportParameterId::ORIGINAL_DESTINATION_CONNECTION_ID);
}
if ((ite = this->_parameters.find(QUICTransportParameterId::PREFERRED_ADDRESS)) != this->_parameters.end()) {
return -(TP_ERROR_MUST_NOT_EXIST | QUICTransportParameterId::PREFERRED_ADDRESS);
}
+ if ((ite = this->_parameters.find(QUICTransportParameterId::RETRY_SOURCE_CONNECTION_ID)) != this->_parameters.end()) {
+ return -(TP_ERROR_MUST_NOT_EXIST | QUICTransportParameterId::RETRY_SOURCE_CONNECTION_ID);
+ }
+
+ if ((ite = this->_parameters.find(QUICTransportParameterId::STATELESS_RESET_TOKEN)) != this->_parameters.end()) {
+ return -(TP_ERROR_MUST_NOT_EXIST | QUICTransportParameterId::STATELESS_RESET_TOKEN);
+ }
+
return 0;
}
@@ -341,18 +358,10 @@ QUICTransportParametersInClientHello::_validate_parameters() const
// QUICTransportParametersInEncryptedExtensions
//
-QUICTransportParametersInEncryptedExtensions::QUICTransportParametersInEncryptedExtensions(const uint8_t *buf, size_t len)
-{
- this->_load(buf, len);
- if (is_debug_tag_set(tag)) {
- this->_print();
- }
-}
-
-void
-QUICTransportParametersInEncryptedExtensions::add_version(QUICVersion version)
+QUICTransportParametersInEncryptedExtensions::QUICTransportParametersInEncryptedExtensions(const uint8_t *buf, size_t len,
+ QUICVersion version)
+ : QUICTransportParameters(buf, len, version)
{
- this->_versions[this->_n_versions++] = version;
}
std::ptrdiff_t
@@ -362,21 +371,36 @@ QUICTransportParametersInEncryptedExtensions::_parameters_offset(const uint8_t *
}
int
-QUICTransportParametersInEncryptedExtensions::_validate_parameters() const
+QUICTransportParametersInEncryptedExtensions::_validate_parameters(QUICVersion version) const
{
- int res = QUICTransportParameters::_validate_parameters();
+ int res = QUICTransportParameters::_validate_parameters(version);
if (res < 0) {
return res;
}
decltype(this->_parameters)::const_iterator ite;
- // MUSTs if the server sent a Retry packet
- if ((ite = this->_parameters.find(QUICTransportParameterId::ORIGINAL_CONNECTION_ID)) != this->_parameters.end()) {
- // We cannot check the length because it's not a fixed length.
- } else {
- // TODO Need a way that checks if we received a Retry from the server
- // return -(TP_ERROR_MUST_EXIST | QUICTransportParameterId::ORIGINAL_CONNECTION_ID);
+ // MUSTs
+ if (version == QUIC_SUPPORTED_VERSIONS[0]) { // draft-28
+ if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_SOURCE_CONNECTION_ID)) != this->_parameters.end()) {
+ // We cannot check the length because it's not a fixed length.
+ } else {
+ return -(TP_ERROR_MUST_EXIST | QUICTransportParameterId::INITIAL_SOURCE_CONNECTION_ID);
+ }
+
+ if ((ite = this->_parameters.find(QUICTransportParameterId::ORIGINAL_DESTINATION_CONNECTION_ID)) != this->_parameters.end()) {
+ // We cannot check the length because it's not a fixed length.
+ } else {
+ return -(TP_ERROR_MUST_EXIST | QUICTransportParameterId::ORIGINAL_DESTINATION_CONNECTION_ID);
+ }
+
+ // MUSTs if the server sent a Retry packet, but MUST NOT if the server did not send a Retry packet
+ // TODO Check if the server sent Retry packet
+ if ((ite = this->_parameters.find(QUICTransportParameterId::RETRY_SOURCE_CONNECTION_ID)) != this->_parameters.end()) {
+ // return -(TP_ERROR_MUST_NOT_EXIST | QUICTransportParameterId::RETRY_SOURCE_CONNECTION_ID);
+ } else {
+ // return -(TP_ERROR_MUST_EXIST | QUICTransportParameterId::RETRY_SOURCE_CONNECTION_ID);
+ }
}
// MAYs
@@ -422,14 +446,15 @@ int
QUICTransportParametersHandler::parse(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char *in, size_t inlen,
X509 *x, size_t chainidx, int *al, void *parse_arg)
{
- QUICTLS *qtls = static_cast<QUICTLS *>(SSL_get_ex_data(s, QUIC::ssl_quic_tls_index));
-
+ QUICTLS *qtls = static_cast<QUICTLS *>(SSL_get_ex_data(s, QUIC::ssl_quic_tls_index));
+ const QUICConnection *qc = static_cast<const QUICConnection *>(SSL_get_ex_data(s, QUIC::ssl_quic_qc_index));
+ QUICVersion version = qc->negotiated_version();
switch (context) {
case SSL_EXT_CLIENT_HELLO:
- qtls->set_remote_transport_parameters(std::make_shared<QUICTransportParametersInClientHello>(in, inlen));
+ qtls->set_remote_transport_parameters(std::make_shared<QUICTransportParametersInClientHello>(in, inlen, version));
break;
case SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS:
- qtls->set_remote_transport_parameters(std::make_shared<QUICTransportParametersInEncryptedExtensions>(in, inlen));
+ qtls->set_remote_transport_parameters(std::make_shared<QUICTransportParametersInEncryptedExtensions>(in, inlen, version));
break;
default:
// Do nothing
diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h
index d3c19fe..7253384 100644
--- a/iocore/net/quic/QUICTransportParameters.h
+++ b/iocore/net/quic/QUICTransportParameters.h
@@ -34,10 +34,10 @@ class QUICTransportParameterId
{
public:
enum {
- ORIGINAL_CONNECTION_ID,
+ ORIGINAL_DESTINATION_CONNECTION_ID,
MAX_IDLE_TIMEOUT,
STATELESS_RESET_TOKEN,
- MAX_PACKET_SIZE,
+ MAX_UDP_PAYLOAD_SIZE,
INITIAL_MAX_DATA,
INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
@@ -49,6 +49,8 @@ public:
DISABLE_ACTIVE_MIGRATION,
PREFERRED_ADDRESS,
ACTIVE_CONNECTION_ID_LIMIT,
+ INITIAL_SOURCE_CONNECTION_ID,
+ RETRY_SOURCE_CONNECTION_ID,
};
explicit operator bool() const { return true; }
@@ -75,7 +77,7 @@ private:
class QUICTransportParameters
{
public:
- QUICTransportParameters(const uint8_t *buf, size_t len);
+ QUICTransportParameters(const uint8_t *buf, size_t len, QUICVersion version);
virtual ~QUICTransportParameters();
bool is_valid() const;
@@ -104,11 +106,11 @@ protected:
};
QUICTransportParameters(){};
- void _load(const uint8_t *buf, size_t len);
+ void _load(const uint8_t *buf, size_t len, QUICVersion version);
bool _valid = false;
virtual std::ptrdiff_t _parameters_offset(const uint8_t *buf) const = 0;
- virtual int _validate_parameters() const;
+ virtual int _validate_parameters(QUICVersion version) const;
void _print() const;
std::map<QUICTransportParameterId, Value *> _parameters;
@@ -118,11 +120,11 @@ class QUICTransportParametersInClientHello : public QUICTransportParameters
{
public:
QUICTransportParametersInClientHello() : QUICTransportParameters(){};
- QUICTransportParametersInClientHello(const uint8_t *buf, size_t len);
+ QUICTransportParametersInClientHello(const uint8_t *buf, size_t len, QUICVersion version);
protected:
std::ptrdiff_t _parameters_offset(const uint8_t *buf) const override;
- int _validate_parameters() const override;
+ int _validate_parameters(QUICVersion version) const override;
private:
};
@@ -131,15 +133,11 @@ class QUICTransportParametersInEncryptedExtensions : public QUICTransportParamet
{
public:
QUICTransportParametersInEncryptedExtensions() : QUICTransportParameters(){};
- QUICTransportParametersInEncryptedExtensions(const uint8_t *buf, size_t len);
- void add_version(QUICVersion version);
+ QUICTransportParametersInEncryptedExtensions(const uint8_t *buf, size_t len, QUICVersion version);
protected:
std::ptrdiff_t _parameters_offset(const uint8_t *buf) const override;
- int _validate_parameters() const override;
-
- uint8_t _n_versions = 0;
- QUICVersion _versions[256] = {};
+ int _validate_parameters(QUICVersion version) const override;
};
class QUICTransportParametersHandler
diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc
index 80a8379..305abc2 100644
--- a/iocore/net/quic/QUICTypes.cc
+++ b/iocore/net/quic/QUICTypes.cc
@@ -153,13 +153,14 @@ QUICTypeUtil::key_phase(QUICPacketType type)
QUICPacketNumberSpace
QUICTypeUtil::pn_space(QUICEncryptionLevel level)
{
+ // TODO Optimize the case order
switch (level) {
case QUICEncryptionLevel::HANDSHAKE:
- return QUICPacketNumberSpace::Handshake;
+ return QUICPacketNumberSpace::HANDSHAKE;
case QUICEncryptionLevel::INITIAL:
- return QUICPacketNumberSpace::Initial;
+ return QUICPacketNumberSpace::INITIAL;
default:
- return QUICPacketNumberSpace::ApplicationData;
+ return QUICPacketNumberSpace::APPLICATION_DATA;
}
}
@@ -360,7 +361,7 @@ QUICResumptionToken::expire_time() const
return QUICIntUtil::read_nbytes_as_uint(this->_token + (1 + 20), 4);
}
-QUICRetryToken::QUICRetryToken(const IpEndpoint &src, QUICConnectionId original_dcid)
+QUICRetryToken::QUICRetryToken(const IpEndpoint &src, QUICConnectionId original_dcid, QUICConnectionId scid)
{
// TODO: read cookie secret from file like SSLTicketKeyConfig
static constexpr char stateless_retry_token_secret[] = "stateless_cookie_secret";
@@ -371,8 +372,14 @@ QUICRetryToken::QUICRetryToken(const IpEndpoint &src, QUICConnectionId original_
data_len = strlen(reinterpret_cast<char *>(data));
size_t cid_len;
+ *(data + data_len) = original_dcid.length();
+ data_len += 1;
QUICTypeUtil::write_QUICConnectionId(original_dcid, data + data_len, &cid_len);
data_len += cid_len;
+ *(data + data_len) = scid.length();
+ data_len += 1;
+ QUICTypeUtil::write_QUICConnectionId(scid, data + data_len, &cid_len);
+ data_len += cid_len;
this->_token[0] = static_cast<uint8_t>(Type::RETRY);
HMAC(EVP_sha1(), stateless_retry_token_secret, sizeof(stateless_retry_token_secret), data, data_len, this->_token + 1,
@@ -380,21 +387,38 @@ QUICRetryToken::QUICRetryToken(const IpEndpoint &src, QUICConnectionId original_
ink_assert(this->_token_len == 20);
this->_token_len += 1;
+ *(this->_token + this->_token_len) = original_dcid.length();
+ this->_token_len += 1;
QUICTypeUtil::write_QUICConnectionId(original_dcid, this->_token + this->_token_len, &cid_len);
this->_token_len += cid_len;
+ *(this->_token + this->_token_len) = scid.length();
+ this->_token_len += 1;
+ QUICTypeUtil::write_QUICConnectionId(scid, this->_token + this->_token_len, &cid_len);
+ this->_token_len += cid_len;
}
bool
QUICRetryToken::is_valid(const IpEndpoint &src) const
{
- return *this == QUICRetryToken(src, this->original_dcid());
+ return *this == QUICRetryToken(src, this->original_dcid(), this->scid());
}
const QUICConnectionId
QUICRetryToken::original_dcid() const
{
// Type uses 1 byte and output of EVP_sha1() should be 160 bits
- return QUICTypeUtil::read_QUICConnectionId(this->_token + (1 + 20), this->_token_len - (1 + 20));
+ auto len = *(this->_token + (1 + 20));
+ auto start = this->_token + (1 + 20 + 1);
+ return QUICTypeUtil::read_QUICConnectionId(start, len);
+}
+
+const QUICConnectionId
+QUICRetryToken::scid() const
+{
+ auto len = *(this->_token + (1 + 20));
+ auto start = this->_token + (1 + 20 + 1 + len + 1);
+ len = *(this->_token + (1 + 20 + 1 + len));
+ return QUICTypeUtil::read_QUICConnectionId(start, len);
}
QUICFrameType
@@ -674,6 +698,18 @@ QUICConnectionId::hex() const
return stream.str();
}
+QUICFrameId
+QUICSentPacketInfo::FrameInfo::id() const
+{
+ return this->_id;
+}
+
+QUICFrameGenerator *
+QUICSentPacketInfo::FrameInfo::generated_by() const
+{
+ return this->_generator;
+}
+
//
// QUICInvariants
//
diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h
index 6441ceb..47e830c 100644
--- a/iocore/net/quic/QUICTypes.h
+++ b/iocore/net/quic/QUICTypes.h
@@ -44,8 +44,7 @@ using QUICPacketNumber = uint64_t;
using QUICVersion = uint32_t;
using QUICStreamId = uint64_t;
using QUICOffset = uint64_t;
-
-static constexpr uint8_t kPacketNumberSpace = 3;
+using QUICFrameId = uint64_t;
// TODO: Update version number
// Note: Prefix for drafts (0xff000000) + draft number
@@ -53,9 +52,11 @@ static constexpr uint8_t kPacketNumberSpace = 3;
// Note: Fix QUIC_ALPN_PROTO_LIST in QUICConfig.cc
// Note: Change ExtensionType (QUICTransportParametersHandler::TRANSPORT_PARAMETER_ID) if it's changed
constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = {
+ 0xff00001d,
0xff00001b,
};
-constexpr QUICVersion QUIC_EXERCISE_VERSION = 0x1a2a3a4a;
+constexpr QUICVersion QUIC_EXERCISE_VERSION1 = 0x1a2a3a4a;
+constexpr QUICVersion QUIC_EXERCISE_VERSION2 = 0x5a6a7a8a;
enum class QUICEncryptionLevel {
NONE = -1,
@@ -75,13 +76,10 @@ constexpr QUICEncryptionLevel QUIC_ENCRYPTION_LEVELS[] = {
QUICEncryptionLevel::ONE_RTT,
};
-// introduce by draft-19 kPacketNumberSpace
-enum class QUICPacketNumberSpace {
- None = -1,
- Initial = 0,
- Handshake = 1,
- ApplicationData = 2,
-};
+// kPacketNumberSpace on Recovery A.2.Constants of Interest
+enum class QUICPacketNumberSpace : int { INITIAL, HANDSHAKE, APPLICATION_DATA, N_SPACES };
+// For conveniece (this removes neccesity of static_cast)
+constexpr int QUIC_N_PACKET_SPACES = static_cast<int>(QUICPacketNumberSpace::N_SPACES);
// Divide to QUICPacketType and QUICPacketLongHeaderType ?
enum class QUICPacketType : uint8_t {
@@ -154,7 +152,7 @@ enum class QUICErrorClass {
enum class QUICTransErrorCode : uint64_t {
NO_ERROR = 0x00,
INTERNAL_ERROR,
- SERVER_BUSY,
+ CONNECTION_REFUSED,
FLOW_CONTROL_ERROR,
STREAM_LIMIT_ERROR,
STREAM_STATE_ERROR,
@@ -164,8 +162,9 @@ enum class QUICTransErrorCode : uint64_t {
CONNECTION_ID_LIMIT_ERROR,
PROTOCOL_VIOLATION,
INVALID_TOKEN,
- CRYPTO_BUFFER_EXCEEDED = 0x0D,
- CRYPTO_ERROR = 0x0100, // 0x100 - 0x1FF
+ APPLICATION_ERROR,
+ CRYPTO_BUFFER_EXCEEDED,
+ CRYPTO_ERROR = 0x0100, // 0x100 - 0x1FF
};
// Application Protocol Error Codes defined in application
@@ -381,7 +380,7 @@ class QUICRetryToken : public QUICAddressValidationToken
{
public:
QUICRetryToken(const uint8_t *buf, size_t len) : QUICAddressValidationToken(buf, len) {}
- QUICRetryToken(const IpEndpoint &src, QUICConnectionId original_dcid);
+ QUICRetryToken(const IpEndpoint &src, QUICConnectionId original_dcid, QUICConnectionId scid);
bool
operator==(const QUICRetryToken &x) const
@@ -395,9 +394,7 @@ public:
bool is_valid(const IpEndpoint &src) const;
const QUICConnectionId original_dcid() const;
-
-private:
- QUICConnectionId _original_dcid;
+ const QUICConnectionId scid() const;
};
class QUICPreferredAddress
@@ -551,13 +548,54 @@ class QUICCCConfig
{
public:
virtual ~QUICCCConfig() {}
- virtual uint32_t max_datagram_size() const = 0;
virtual uint32_t initial_window() const = 0;
virtual uint32_t minimum_window() const = 0;
virtual float loss_reduction_factor() const = 0;
virtual uint32_t persistent_congestion_threshold() const = 0;
};
+class QUICFrameGenerator;
+
+struct QUICSentPacketInfo {
+ class FrameInfo
+ {
+ public:
+ FrameInfo(QUICFrameId id, QUICFrameGenerator *generator) : _id(id), _generator(generator) {}
+
+ QUICFrameId id() const;
+ QUICFrameGenerator *generated_by() const;
+
+ private:
+ QUICFrameId _id = 0;
+ QUICFrameGenerator *_generator;
+ };
+
+ // Recovery A.1.1. Sent Packet Fields
+ QUICPacketNumber packet_number;
+ bool ack_eliciting;
+ bool in_flight;
+ size_t sent_bytes;
+ ink_hrtime time_sent;
+
+ // Additional fields
+ QUICPacketType type;
+ std::vector<FrameInfo> frames;
+ QUICPacketNumberSpace pn_space;
+ // End of additional fields
+};
+
+using QUICSentPacketInfoUPtr = std::unique_ptr<QUICSentPacketInfo>;
+
+class QUICRTTProvider
+{
+public:
+ virtual ink_hrtime smoothed_rtt() const = 0;
+ virtual ink_hrtime rttvar() const = 0;
+ virtual ink_hrtime latest_rtt() const = 0;
+
+ virtual ink_hrtime congestion_period(uint32_t threshold) const = 0;
+};
+
// TODO: move version independent functions to QUICInvariants
class QUICTypeUtil
{
diff --git a/iocore/net/quic/qlog/QLogListener.h b/iocore/net/quic/qlog/QLogListener.h
index 7b55af2c..9337b07 100644
--- a/iocore/net/quic/qlog/QLogListener.h
+++ b/iocore/net/quic/qlog/QLogListener.h
@@ -73,7 +73,7 @@ public:
};
void
- packet_lost_callback(QUICCallbackContext &, const QUICPacketInfo &packet) override
+ packet_lost_callback(QUICCallbackContext &, const QUICSentPacketInfo &packet) override
{
auto qe = std::make_unique<Recovery::PacketLost>(PacketTypeToName(packet.type), packet.packet_number);
this->_log.last_trace().push_event(std::move(qe));
diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc
index 2b66f06..eb96869 100644
--- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc
+++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc
@@ -283,7 +283,7 @@ TEST_CASE("QUICAckFrameManager_loss_recover", "[quic]")
TEST_CASE("QUICAckFrameManager_QUICAckFrameCreator", "[quic]")
{
QUICAckFrameManager ack_manager;
- QUICAckFrameManager::QUICAckFrameCreator packet_numbers(QUICPacketNumberSpace::Initial, &ack_manager);
+ QUICAckFrameManager::QUICAckFrameCreator packet_numbers(QUICPacketNumberSpace::INITIAL, &ack_manager);
CHECK(packet_numbers.size() == 0);
CHECK(packet_numbers.largest_ack_number() == 0);
diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc
index 4a71a07..e697868 100644
--- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc
+++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc
@@ -33,11 +33,12 @@
#include <openssl/ssl.h>
-// #include "Mock.h"
#include "QUICPacketHeaderProtector.h"
#include "QUICPacketPayloadProtector.h"
#include "QUICPacketProtectionKeyInfo.h"
#include "QUICTLS.h"
+#include "QUICGlobals.h"
+#include "Mock.h"
// XXX For NetVCOptions::reset
struct PollCont;
@@ -107,8 +108,12 @@ TEST_CASE("QUICHandshakeProtocol")
QUICPacketProtectionKeyInfo pp_key_info_client;
QUICPacketProtectionKeyInfo pp_key_info_server;
NetVCOptions netvc_options;
+ MockQUICConnection mock_client_connection;
+ MockQUICConnection mock_server_connection;
QUICHandshakeProtocol *client = new QUICTLS(pp_key_info_client, client_ssl_ctx, NET_VCONNECTION_OUT, netvc_options);
QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN, netvc_options);
+ SSL_set_ex_data(static_cast<QUICTLS *>(client)->ssl_handle(), QUIC::ssl_quic_qc_index, &mock_client_connection);
+ SSL_set_ex_data(static_cast<QUICTLS *>(server)->ssl_handle(), QUIC::ssl_quic_qc_index, &mock_server_connection);
QUICPacketPayloadProtector ppp_client(pp_key_info_client);
QUICPacketPayloadProtector ppp_server(pp_key_info_server);
@@ -119,8 +124,10 @@ TEST_CASE("QUICHandshakeProtocol")
client->set_local_transport_parameters(client_tp);
server->set_local_transport_parameters(server_tp);
- CHECK(client->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8}));
- CHECK(server->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8}));
+ CHECK(client->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8},
+ QUIC_SUPPORTED_VERSIONS[0]));
+ CHECK(server->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8},
+ QUIC_SUPPORTED_VERSIONS[0]));
// CH
QUICHandshakeMsgs msg0;
@@ -232,8 +239,12 @@ TEST_CASE("QUICHandshakeProtocol")
QUICPacketProtectionKeyInfo pp_key_info_client;
QUICPacketProtectionKeyInfo pp_key_info_server;
NetVCOptions netvc_options;
+ MockQUICConnection mock_client_connection;
+ MockQUICConnection mock_server_connection;
QUICHandshakeProtocol *client = new QUICTLS(pp_key_info_client, client_ssl_ctx, NET_VCONNECTION_OUT, netvc_options);
QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN, netvc_options);
+ SSL_set_ex_data(static_cast<QUICTLS *>(client)->ssl_handle(), QUIC::ssl_quic_qc_index, &mock_client_connection);
+ SSL_set_ex_data(static_cast<QUICTLS *>(server)->ssl_handle(), QUIC::ssl_quic_qc_index, &mock_server_connection);
QUICPacketPayloadProtector ppp_client(pp_key_info_client);
QUICPacketPayloadProtector ppp_server(pp_key_info_server);
@@ -244,8 +255,10 @@ TEST_CASE("QUICHandshakeProtocol")
client->set_local_transport_parameters(client_tp);
server->set_local_transport_parameters(server_tp);
- CHECK(client->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8}));
- CHECK(server->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8}));
+ CHECK(client->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8},
+ QUIC_SUPPORTED_VERSIONS[0]));
+ CHECK(server->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8},
+ QUIC_SUPPORTED_VERSIONS[0]));
// CH
QUICHandshakeMsgs msg0;
@@ -369,7 +382,8 @@ TEST_CASE("QUICHandshakeProtocol")
QUICPacketProtectionKeyInfo pp_key_info_server;
NetVCOptions netvc_options;
QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN, netvc_options);
- CHECK(server->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8}));
+ CHECK(server->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8},
+ QUIC_SUPPORTED_VERSIONS[0]));
// Malformed CH (finished)
uint8_t msg1_buf[] = {0x14, 0x00, 0x00, 0x30, 0x35, 0xb9, 0x82, 0x9d, 0xb9, 0x14, 0x70, 0x03, 0x60,
@@ -401,8 +415,12 @@ TEST_CASE("QUICHandshakeProtocol")
QUICPacketProtectionKeyInfo pp_key_info_client;
QUICPacketProtectionKeyInfo pp_key_info_server;
NetVCOptions netvc_options;
+ MockQUICConnection mock_client_connection;
+ MockQUICConnection mock_server_connection;
QUICHandshakeProtocol *client = new QUICTLS(pp_key_info_client, client_ssl_ctx, NET_VCONNECTION_OUT, netvc_options);
QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN, netvc_options);
+ SSL_set_ex_data(static_cast<QUICTLS *>(client)->ssl_handle(), QUIC::ssl_quic_qc_index, &mock_client_connection);
+ SSL_set_ex_data(static_cast<QUICTLS *>(server)->ssl_handle(), QUIC::ssl_quic_qc_index, &mock_server_connection);
auto client_tp = std::make_shared<QUICTransportParametersInClientHello>();
auto server_tp = std::make_shared<QUICTransportParametersInEncryptedExtensions>();
@@ -411,8 +429,10 @@ TEST_CASE("QUICHandshakeProtocol")
client->set_local_transport_parameters(client_tp);
server->set_local_transport_parameters(server_tp);
- CHECK(client->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8}));
- CHECK(server->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8}));
+ CHECK(client->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8},
+ QUIC_SUPPORTED_VERSIONS[0]));
+ CHECK(server->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8},
+ QUIC_SUPPORTED_VERSIONS[0]));
// # Start Handshake
diff --git a/iocore/net/quic/test/test_QUICKeyGenerator.cc b/iocore/net/quic/test/test_QUICKeyGenerator.cc
index 4c1858a..cd9ff38 100644
--- a/iocore/net/quic/test/test_QUICKeyGenerator.cc
+++ b/iocore/net/quic/test/test_QUICKeyGenerator.cc
@@ -35,8 +35,8 @@
#include "QUICKeyGenerator.h"
#include "QUICPacketProtectionKeyInfo.h"
-// https://github.com/quicwg/base-drafts/wiki/Test-Vector-for-the-Clear-Text-AEAD-key-derivation
-TEST_CASE("draft-23 Test Vectors", "[quic]")
+// https://github.com/quicwg/base-drafts/wiki/Test-Vector-for-the-Initial-AEAD-key-derivation
+TEST_CASE("draft-23~27 Test Vectors", "[quic]")
{
SECTION("CLIENT Initial")
{
@@ -51,8 +51,9 @@ TEST_CASE("draft-23 Test Vectors", "[quic]")
QUICPacketProtectionKeyInfo pp_key_info;
pp_key_info.set_cipher_initial(EVP_aes_128_gcm());
pp_key_info.set_cipher_for_hp_initial(EVP_aes_128_ecb());
- keygen.generate(pp_key_info.encryption_key_for_hp(QUICKeyPhase::INITIAL), pp_key_info.encryption_key(QUICKeyPhase::INITIAL),
- pp_key_info.encryption_iv(QUICKeyPhase::INITIAL), pp_key_info.encryption_iv_len(QUICKeyPhase::INITIAL), cid);
+ keygen.generate(0xff00001b, pp_key_info.encryption_key_for_hp(QUICKeyPhase::INITIAL),
+ pp_key_info.encryption_key(QUICKeyPhase::INITIAL), pp_key_info.encryption_iv(QUICKeyPhase::INITIAL),
+ pp_key_info.encryption_iv_len(QUICKeyPhase::INITIAL), cid);
CHECK(pp_key_info.encryption_key_len(QUICKeyPhase::INITIAL) == sizeof(expected_client_key));
CHECK(memcmp(pp_key_info.encryption_key(QUICKeyPhase::INITIAL), expected_client_key, sizeof(expected_client_key)) == 0);
@@ -76,8 +77,9 @@ TEST_CASE("draft-23 Test Vectors", "[quic]")
QUICPacketProtectionKeyInfo pp_key_info;
pp_key_info.set_cipher_initial(EVP_aes_128_gcm());
pp_key_info.set_cipher_for_hp_initial(EVP_aes_128_ecb());
- keygen.generate(pp_key_info.encryption_key_for_hp(QUICKeyPhase::INITIAL), pp_key_info.encryption_key(QUICKeyPhase::INITIAL),
- pp_key_info.encryption_iv(QUICKeyPhase::INITIAL), pp_key_info.encryption_iv_len(QUICKeyPhase::INITIAL), cid);
+ keygen.generate(0xff00001b, pp_key_info.encryption_key_for_hp(QUICKeyPhase::INITIAL),
+ pp_key_info.encryption_key(QUICKeyPhase::INITIAL), pp_key_info.encryption_iv(QUICKeyPhase::INITIAL),
+ pp_key_info.encryption_iv_len(QUICKeyPhase::INITIAL), cid);
CHECK(pp_key_info.encryption_key_len(QUICKeyPhase::INITIAL) == sizeof(expected_server_key));
CHECK(memcmp(pp_key_info.encryption_key(QUICKeyPhase::INITIAL), expected_server_key, sizeof(expected_server_key)) == 0);
diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc
index acabd82..5dd8271 100644
--- a/iocore/net/quic/test/test_QUICLossDetector.cc
+++ b/iocore/net/quic/test/test_QUICLossDetector.cc
@@ -27,6 +27,8 @@
#include "QUICPacketFactory.h"
#include "QUICAckFrameCreator.h"
#include "QUICEvents.h"
+#include "QUICPacketFactory.h"
+#include "QUICAckFrameCreator.h"
#include "Mock.h"
#include "tscore/ink_hrtime.h"
@@ -79,16 +81,15 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]")
{reinterpret_cast<const uint8_t *>("\x11\x12\x13\x14\x15\x16\x17\x18"), 8}, sizeof(raw), 0, true, true, false);
handshake_packet->attach_payload(payload, true);
QUICPacketUPtr packet = QUICPacketUPtr(handshake_packet, [](QUICPacket *p) { delete p; });
- detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{
+ detector.on_packet_sent(QUICSentPacketInfoUPtr(new QUICSentPacketInfo{
packet->packet_number(),
- Thread::get_hrtime(),
packet->is_ack_eliciting(),
- static_cast<QUICLongHeaderPacket &>(*packet).is_crypto_packet(),
true,
packet->size(),
+ Thread::get_hrtime(),
packet->type(),
{},
- QUICPacketNumberSpace::Handshake,
+ QUICPacketNumberSpace::HANDSHAKE,
}));
ink_hrtime_sleep(HRTIME_MSECONDS(1000));
CHECK(g.lost_frame_count >= 0);
@@ -106,7 +107,7 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]")
SECTION("1-RTT")
{
// Send packet (1) to (7)
- QUICPacketNumberSpace pn_space = QUICPacketNumberSpace::ApplicationData;
+ QUICPacketNumberSpace pn_space = QUICPacketNumberSpace::APPLICATION_DATA;
QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT;
payload = make_ptr<IOBufferBlock>(new_IOBufferBlock());
payload->alloc(iobuffer_size_to_index(payload_len, BUFFER_SIZE_INDEX_32K));
@@ -181,97 +182,87 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]")
QUICPacketNumber pn9 = packet9->packet_number();
QUICPacketNumber pn10 = packet10->packet_number();
- QUICPacketInfoUPtr packet_info = nullptr;
- detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet1->packet_number(),
- Thread::get_hrtime(),
- packet1->is_ack_eliciting(),
- false,
- true,
- packet1->size(),
- packet1->type(),
- {},
- pn_space}));
- detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet2->packet_number(),
- Thread::get_hrtime(),
- packet2->is_ack_eliciting(),
- false,
- true,
- packet2->size(),
- packet2->type(),
- {},
- pn_space}));
- detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet3->packet_number(),
- Thread::get_hrtime(),
- packet3->is_ack_eliciting(),
- false,
- true,
- packet3->size(),
- packet3->type(),
- {},
- pn_space}));
- detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet4->packet_number(),
- Thread::get_hrtime(),
- packet4->is_ack_eliciting(),
- false,
- true,
- packet4->size(),
- packet4->type(),
- {},
- pn_space}));
- detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet5->packet_number(),
- Thread::get_hrtime(),
- packet5->is_ack_eliciting(),
- false,
- true,
- packet5->size(),
- packet5->type(),
- {},
- pn_space}));
- detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet6->packet_number(),
- Thread::get_hrtime(),
- packet6->is_ack_eliciting(),
- false,
- true,
- packet6->size(),
- packet6->type(),
- {},
- pn_space}));
- detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet7->packet_number(),
- Thread::get_hrtime(),
- packet6->is_ack_eliciting(),
- false,
- true,
- packet7->size(),
- packet7->type(),
- {},
- pn_space}));
- detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet8->packet_number(),
- Thread::get_hrtime(),
- packet6->is_ack_eliciting(),
- false,
- true,
- packet8->size(),
- packet8->type(),
- {},
- pn_space}));
- detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet9->packet_number(),
- Thread::get_hrtime(),
- packet6->is_ack_eliciting(),
- false,
- true,
- packet9->size(),
- packet9->type(),
- {},
- pn_space}));
- detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet10->packet_number(),
- Thread::get_hrtime(),
- packet10->is_ack_eliciting(),
- false,
- true,
- packet10->size(),
- packet10->type(),
- {},
- pn_space}));
+ QUICSentPacketInfoUPtr packet_info = nullptr;
+ detector.on_packet_sent(QUICSentPacketInfoUPtr(new QUICSentPacketInfo{packet1->packet_number(),
+ packet1->is_ack_eliciting(),
+ true,
+ packet1->size(),
+ Thread::get_hrtime(),
+ packet1->type(),
+ {},
+ pn_space}));
+ detector.on_packet_sent(QUICSentPacketInfoUPtr(new QUICSentPacketInfo{packet2->packet_number(),
+ packet2->is_ack_eliciting(),
+ true,
+ packet2->size(),
+ Thread::get_hrtime(),
+ packet2->type(),
+ {},
+ pn_space}));
+ detector.on_packet_sent(QUICSentPacketInfoUPtr(new QUICSentPacketInfo{packet3->packet_number(),
+ packet3->is_ack_eliciting(),
+ true,
+ packet3->size(),
+ Thread::get_hrtime(),
+ packet3->type(),
+ {},
+ pn_space}));
+ detector.on_packet_sent(QUICSentPacketInfoUPtr(new QUICSentPacketInfo{packet4->packet_number(),
+ packet4->is_ack_eliciting(),
+ true,
+ packet4->size(),
+ Thread::get_hrtime(),
+ packet4->type(),
+ {},
+ pn_space}));
+ detector.on_packet_sent(QUICSentPacketInfoUPtr(new QUICSentPacketInfo{packet5->packet_number(),
+ packet5->is_ack_eliciting(),
+ true,
+ packet5->size(),
+ Thread::get_hrtime(),
+ packet5->type(),
+ {},
+ pn_space}));
+ detector.on_packet_sent(QUICSentPacketInfoUPtr(new QUICSentPacketInfo{packet6->packet_number(),
+ packet6->is_ack_eliciting(),
+ true,
+ packet6->size(),
+ Thread::get_hrtime(),
+ packet6->type(),
+ {},
+ pn_space}));
+ detector.on_packet_sent(QUICSentPacketInfoUPtr(new QUICSentPacketInfo{packet7->packet_number(),
+ packet6->is_ack_eliciting(),
+ true,
+ packet7->size(),
+ Thread::get_hrtime(),
+ packet7->type(),
+ {},
+ pn_space}));
+ detector.on_packet_sent(QUICSentPacketInfoUPtr(new QUICSentPacketInfo{packet8->packet_number(),
+ packet6->is_ack_eliciting(),
+ true,
+ packet8->size(),
+ Thread::get_hrtime(),
+ packet8->type(),
+ {},
+ pn_space}));
+ detector.on_packet_sent(QUICSentPacketInfoUPtr(new QUICSentPacketInfo{packet9->packet_number(),
+ packet6->is_ack_eliciting(),
+ true,
+ packet9->size(),
+ Thread::get_hrtime(),
+ packet9->type(),
+ {},
+ pn_space}));
+ detector.on_packet_sent(QUICSentPacketInfoUPtr(new QUICSentPacketInfo{packet10->packet_number(),
+ packet10->is_ack_eliciting(),
+ true,
+ packet10->size(),
+ Thread::get_hrtime(),
+ packet10->type(),
+ {},
+ pn_space}));
ink_hrtime_sleep(HRTIME_MSECONDS(2000));
// Receive an ACK for (1) (4) (5) (7) (8) (9)
diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc
index 5dda30a..35ffd5e 100644
--- a/iocore/net/quic/test/test_QUICPacket.cc
+++ b/iocore/net/quic/test/test_QUICPacket.cc
@@ -44,7 +44,7 @@ TEST_CASE("Receiving Packet", "[quic]")
0x08, // SCID Len
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID
0x00, 0x00, 0x00, 0x08, // Supported Version 1
- 0x00, 0x00, 0x00, 0x09, // Supported Version 1
+ 0x00, 0x00, 0x00, 0x09, // Supported Version 2
};
Ptr<IOBufferBlock> input_ibb = make_ptr<IOBufferBlock>(new_IOBufferBlock());
input_ibb->set_internal(static_cast<void *>(input), sizeof(input), BUFFER_SIZE_NOT_ALLOCATED);
@@ -255,8 +255,8 @@ TEST_CASE("Sending Packet", "[quic]")
SECTION("RETRY Packet (store)")
{
- uint8_t buf[64] = {0};
- size_t len = 0;
+ uint8_t buf[128] = {0};
+ size_t len = 0;
const uint8_t expected[] = {
0xf0, // Long header, Type: RETRY
@@ -267,11 +267,13 @@ TEST_CASE("Sending Packet", "[quic]")
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID
0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // Retry Token
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, //
- 0x10, 0x11, 0x12, 0x13, 0x14, 0xf0, 0xf1, 0xf2, //
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x08, 0x01, 0x02, //
+ 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x08, 0x11, //
+ 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Retry Integrity Tag
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
- QUICRetryToken token(expected + 23, 24);
+ QUICRetryToken token(expected + 23, 39);
QUICRetryPacket packet(0x11223344, {reinterpret_cast<const uint8_t *>("\x01\x02\x03\x04\x05\x06\x07\x08"), 8},
{reinterpret_cast<const uint8_t *>("\x11\x12\x13\x14\x15\x16\x17\x18"), 8}, token);
@@ -285,6 +287,21 @@ TEST_CASE("Sending Packet", "[quic]")
CHECK(len == packet.size());
CHECK(memcmp(buf, expected, sizeof(expected) - 16) == 0);
}
+
+ SECTION("VersionNegotiation Packet")
+ {
+ QUICConnectionId dummy;
+ QUICVersionNegotiationPacket vn1(dummy, dummy, QUIC_SUPPORTED_VERSIONS, countof(QUIC_SUPPORTED_VERSIONS),
+ QUIC_EXERCISE_VERSION1);
+ for (auto i = 0; i < vn1.nversions(); ++i) {
+ REQUIRE(vn1.versions()[i] != QUIC_EXERCISE_VERSION1);
+ }
+ QUICVersionNegotiationPacket vn2(dummy, dummy, QUIC_SUPPORTED_VERSIONS, countof(QUIC_SUPPORTED_VERSIONS),
+ QUIC_EXERCISE_VERSION2);
+ for (auto i = 0; i < vn2.nversions(); ++i) {
+ REQUIRE(vn2.versions()[i] != QUIC_EXERCISE_VERSION2);
+ }
+ }
}
TEST_CASE("Encoded Packet Number Length", "[quic]")
diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc
index 0df3436..57bf6b3 100644
--- a/iocore/net/quic/test/test_QUICPacketFactory.cc
+++ b/iocore/net/quic/test/test_QUICPacketFactory.cc
@@ -37,7 +37,7 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]")
QUICConnectionId dcid(raw_dcid, 8);
QUICConnectionId scid(raw_scid, 8);
- QUICPacketUPtr packet = factory.create_version_negotiation_packet(scid, dcid);
+ QUICPacketUPtr packet = factory.create_version_negotiation_packet(scid, dcid, QUIC_EXERCISE_VERSION1);
REQUIRE(packet != nullptr);
QUICVersionNegotiationPacket &vn_packet = static_cast<QUICVersionNegotiationPacket &>(*packet);
@@ -56,8 +56,9 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]")
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Destination Connection ID
0x08, // SCID Len
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Source Connection ID
+ 0xff, 0x00, 0x00, 0x1d, // Supported Version
0xff, 0x00, 0x00, 0x1b, // Supported Version
- 0x1a, 0x2a, 0x3a, 0x4a, // Exercise Version
+ 0x5a, 0x6a, 0x7a, 0x8a, // Exercise Version
};
uint8_t buf[1024] = {0};
size_t buf_len;
@@ -75,9 +76,9 @@ TEST_CASE("QUICPacketFactory_Create_Retry", "[quic]")
uint8_t raw[] = {0xaa, 0xbb, 0xcc, 0xdd};
QUICRetryToken token(raw, 4);
- QUICPacketUPtr packet =
- factory.create_retry_packet(QUICConnectionId(reinterpret_cast<const uint8_t *>("\x01\x02\x03\x04"), 4),
- QUICConnectionId(reinterpret_cast<const uint8_t *>("\x11\x12\x13\x14"), 4), token);
+ QUICPacketUPtr packet = factory.create_retry_packet(
+ QUIC_SUPPORTED_VERSIONS[0], QUICConnectionId(reinterpret_cast<const uint8_t *>("\x01\x02\x03\x04"), 4),
+ QUICConnectionId(reinterpret_cast<const uint8_t *>("\x11\x12\x13\x14"), 4), token);
REQUIRE(packet != nullptr);
diff --git a/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc b/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc
index 031aa51..0625595 100644
--- a/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc
+++ b/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc
@@ -26,6 +26,8 @@
#include "QUICPacketProtectionKeyInfo.h"
#include "QUICPacketHeaderProtector.h"
#include "QUICTLS.h"
+#include "QUICGlobals.h"
+#include "Mock.h"
struct PollCont;
#include "P_UDPConnection.h"
@@ -87,8 +89,10 @@ TEST_CASE("QUICPacketHeaderProtector")
QUICHandshakeProtocol *client = new QUICTLS(pp_key_info_client, client_ssl_ctx, NET_VCONNECTION_OUT, netvc_options);
QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN, netvc_options);
- CHECK(client->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8}));
- CHECK(server->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8}));
+ CHECK(client->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8},
+ QUIC_SUPPORTED_VERSIONS[0]));
+ CHECK(server->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8},
+ QUIC_SUPPORTED_VERSIONS[0]));
QUICPacketHeaderProtector client_ph_protector(pp_key_info_client);
QUICPacketHeaderProtector server_ph_protector(pp_key_info_server);
@@ -121,8 +125,12 @@ TEST_CASE("QUICPacketHeaderProtector")
QUICPacketProtectionKeyInfo pp_key_info_client;
QUICPacketProtectionKeyInfo pp_key_info_server;
NetVCOptions netvc_options;
+ MockQUICConnection mock_client_connection;
+ MockQUICConnection mock_server_connection;
QUICHandshakeProtocol *client = new QUICTLS(pp_key_info_client, client_ssl_ctx, NET_VCONNECTION_OUT, netvc_options);
QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN, netvc_options);
+ SSL_set_ex_data(static_cast<QUICTLS *>(client)->ssl_handle(), QUIC::ssl_quic_qc_index, &mock_client_connection);
+ SSL_set_ex_data(static_cast<QUICTLS *>(server)->ssl_handle(), QUIC::ssl_quic_qc_index, &mock_server_connection);
auto client_tp = std::make_shared<QUICTransportParametersInClientHello>();
auto server_tp = std::make_shared<QUICTransportParametersInEncryptedExtensions>();
@@ -131,8 +139,10 @@ TEST_CASE("QUICPacketHeaderProtector")
client->set_local_transport_parameters(client_tp);
server->set_local_transport_parameters(server_tp);
- CHECK(client->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8}));
- CHECK(server->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8}));
+ CHECK(client->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8},
+ QUIC_SUPPORTED_VERSIONS[0]));
+ CHECK(server->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8},
+ QUIC_SUPPORTED_VERSIONS[0]));
QUICPacketHeaderProtector client_ph_protector(pp_key_info_client);
QUICPacketHeaderProtector server_ph_protector(pp_key_info_server);
diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc
index 8d7ddf2..ad9443d 100644
--- a/iocore/net/quic/test/test_QUICStreamManager.cc
+++ b/iocore/net/quic/test/test_QUICStreamManager.cc
@@ -47,7 +47,7 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]")
0x40, 0x10 // value
};
std::shared_ptr<QUICTransportParameters> local_tp =
- std::make_shared<QUICTransportParametersInEncryptedExtensions>(local_tp_buf, sizeof(local_tp_buf));
+ std::make_shared<QUICTransportParametersInEncryptedExtensions>(local_tp_buf, sizeof(local_tp_buf), QUIC_SUPPORTED_VERSIONS[0]);
uint8_t remote_tp_buf[] = {
0x08, // parameter id - initial_max_streams_bidi
@@ -55,7 +55,7 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]")
0x40, 0x10 // value
};
std::shared_ptr<QUICTransportParameters> remote_tp =
- std::make_shared<QUICTransportParametersInClientHello>(remote_tp_buf, sizeof(remote_tp_buf));
+ std::make_shared<QUICTransportParametersInClientHello>(remote_tp_buf, sizeof(remote_tp_buf), QUIC_SUPPORTED_VERSIONS[0]);
sm.init_flow_control_params(local_tp, remote_tp);
@@ -139,7 +139,7 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]")
0xbf, 0xff, 0xff, 0xff // value
};
std::shared_ptr<QUICTransportParameters> local_tp =
- std::make_shared<QUICTransportParametersInEncryptedExtensions>(local_tp_buf, sizeof(local_tp_buf));
+ std::make_shared<QUICTransportParametersInEncryptedExtensions>(local_tp_buf, sizeof(local_tp_buf), QUIC_SUPPORTED_VERSIONS[0]);
uint8_t remote_tp_buf[] = {
0x08, // parameter id - initial_max_streams_bidi
@@ -150,7 +150,7 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]")
0xbf, 0xff, 0xff, 0xff // value
};
std::shared_ptr<QUICTransportParameters> remote_tp =
- std::make_shared<QUICTransportParametersInClientHello>(remote_tp_buf, sizeof(remote_tp_buf));
+ std::make_shared<QUICTransportParametersInClientHello>(remote_tp_buf, sizeof(remote_tp_buf), QUIC_SUPPORTED_VERSIONS[0]);
sm.init_flow_control_params(local_tp, remote_tp);
@@ -194,7 +194,7 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]")
0xbf, 0xff, 0xff, 0xff // value
};
std::shared_ptr<QUICTransportParameters> local_tp =
- std::make_shared<QUICTransportParametersInEncryptedExtensions>(local_tp_buf, sizeof(local_tp_buf));
+ std::make_shared<QUICTransportParametersInEncryptedExtensions>(local_tp_buf, sizeof(local_tp_buf), QUIC_SUPPORTED_VERSIONS[0]);
uint8_t remote_tp_buf[] = {
0x08, // parameter id - initial_max_streams_bidi
@@ -205,7 +205,7 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]")
0xbf, 0xff, 0xff, 0xff // value
};
std::shared_ptr<QUICTransportParameters> remote_tp =
- std::make_shared<QUICTransportParametersInClientHello>(remote_tp_buf, sizeof(remote_tp_buf));
+ std::make_shared<QUICTransportParametersInClientHello>(remote_tp_buf, sizeof(remote_tp_buf), QUIC_SUPPORTED_VERSIONS[0]);
sm.init_flow_control_params(local_tp, remote_tp);
@@ -262,7 +262,7 @@ TEST_CASE("QUICStreamManager_max_streams", "[quic]")
0x03, // value
};
std::shared_ptr<QUICTransportParameters> local_tp =
- std::make_shared<QUICTransportParametersInEncryptedExtensions>(local_tp_buf, sizeof(local_tp_buf));
+ std::make_shared<QUICTransportParametersInEncryptedExtensions>(local_tp_buf, sizeof(local_tp_buf), QUIC_SUPPORTED_VERSIONS[0]);
uint8_t remote_tp_buf[] = {
0x08, // parameter id - initial_max_streams_bidi
@@ -273,7 +273,7 @@ TEST_CASE("QUICStreamManager_max_streams", "[quic]")
0x03, // value
};
std::shared_ptr<QUICTransportParameters> remote_tp =
- std::make_shared<QUICTransportParametersInClientHello>(remote_tp_buf, sizeof(remote_tp_buf));
+ std::make_shared<QUICTransportParametersInClientHello>(remote_tp_buf, sizeof(remote_tp_buf), QUIC_SUPPORTED_VERSIONS[0]);
sm.init_flow_control_params(local_tp, remote_tp);
diff --git a/iocore/net/quic/test/test_QUICTransportParameters.cc b/iocore/net/quic/test/test_QUICTransportParameters.cc
index a225b86..cddad46 100644
--- a/iocore/net/quic/test/test_QUICTransportParameters.cc
+++ b/iocore/net/quic/test/test_QUICTransportParameters.cc
@@ -44,13 +44,13 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]")
0x05, 0x67, // value
};
- QUICTransportParametersInClientHello params_in_ch(buf, sizeof(buf));
+ QUICTransportParametersInClientHello params_in_ch(buf, sizeof(buf), QUIC_SUPPORTED_VERSIONS[0]);
CHECK(params_in_ch.is_valid());
uint16_t len = 0;
const uint8_t *data = nullptr;
- data = params_in_ch.getAsBytes(QUICTransportParameterId::ORIGINAL_CONNECTION_ID, len);
+ data = params_in_ch.getAsBytes(QUICTransportParameterId::ORIGINAL_DESTINATION_CONNECTION_ID, len);
CHECK(len == 4);
CHECK(memcmp(data, "\x11\x22\x33\x44", 4) == 0);
@@ -62,7 +62,7 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]")
CHECK(len == 2);
CHECK(memcmp(data, "\x0a\x0b", 2) == 0);
- data = params_in_ch.getAsBytes(QUICTransportParameterId::MAX_PACKET_SIZE, len);
+ data = params_in_ch.getAsBytes(QUICTransportParameterId::MAX_UDP_PAYLOAD_SIZE, len);
CHECK(len == 2);
CHECK(memcmp(data, "\x05\x67", 2) == 0);
@@ -82,7 +82,7 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]")
0x12, 0x34, 0x56, 0x78, // value
};
- QUICTransportParametersInClientHello params_in_ch(buf, sizeof(buf));
+ QUICTransportParametersInClientHello params_in_ch(buf, sizeof(buf), QUIC_SUPPORTED_VERSIONS[0]);
CHECK(!params_in_ch.is_valid());
}
}
@@ -111,7 +111,7 @@ TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]")
params_in_ch.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, max_stream_data);
uint16_t max_packet_size = 0x1bcd;
- params_in_ch.set(QUICTransportParameterId::MAX_PACKET_SIZE, max_packet_size);
+ params_in_ch.set(QUICTransportParameterId::MAX_UDP_PAYLOAD_SIZE, max_packet_size);
uint8_t stateless_reset_token[16] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
@@ -142,7 +142,7 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]")
0x91, 0x22, 0x33, 0x44, // value
};
- QUICTransportParametersInEncryptedExtensions params_in_ee(buf, sizeof(buf));
+ QUICTransportParametersInEncryptedExtensions params_in_ee(buf, sizeof(buf), QUIC_SUPPORTED_VERSIONS[0]);
CHECK(params_in_ee.is_valid());
uint16_t len = 0;
@@ -183,7 +183,7 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]")
0x00, // length of value
};
- QUICTransportParametersInEncryptedExtensions params_in_ee(buf, sizeof(buf));
+ QUICTransportParametersInEncryptedExtensions params_in_ee(buf, sizeof(buf), QUIC_SUPPORTED_VERSIONS[0]);
CHECK(params_in_ee.is_valid());
uint16_t len = 0;
@@ -215,7 +215,7 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]")
0x12, 0x34, 0x56, 0x78, // value
};
- QUICTransportParametersInEncryptedExtensions params_in_ee(buf, sizeof(buf));
+ QUICTransportParametersInEncryptedExtensions params_in_ee(buf, sizeof(buf), QUIC_SUPPORTED_VERSIONS[0]);
CHECK(!params_in_ee.is_valid());
}
}
@@ -242,10 +242,8 @@ TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]")
params_in_ee.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, max_stream_data);
uint16_t max_packet_size = 0x1bcd;
- params_in_ee.set(QUICTransportParameterId::MAX_PACKET_SIZE, max_packet_size);
+ params_in_ee.set(QUICTransportParameterId::MAX_UDP_PAYLOAD_SIZE, max_packet_size);
- params_in_ee.add_version(0x01020304);
- params_in_ee.add_version(0x05060708);
params_in_ee.store(buf, &len);
CHECK(len == 10);
CHECK(memcmp(buf, expected, len) == 0);
@@ -273,11 +271,9 @@ TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]")
params_in_ee.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, max_stream_data);
uint16_t max_packet_size = 0x1bcd;
- params_in_ee.set(QUICTransportParameterId::MAX_PACKET_SIZE, max_packet_size);
+ params_in_ee.set(QUICTransportParameterId::MAX_UDP_PAYLOAD_SIZE, max_packet_size);
params_in_ee.set(QUICTransportParameterId::DISABLE_ACTIVE_MIGRATION, nullptr, 0);
- params_in_ee.add_version(0x01020304);
- params_in_ee.add_version(0x05060708);
params_in_ee.store(buf, &len);
CHECK(len == 12);
CHECK(memcmp(buf, expected, len) == 0);
diff --git a/iocore/net/quic/test/test_QUICType.cc b/iocore/net/quic/test/test_QUICType.cc
index fb45c44..b08085c 100644
--- a/iocore/net/quic/test/test_QUICType.cc
+++ b/iocore/net/quic/test/test_QUICType.cc
@@ -103,11 +103,14 @@ TEST_CASE("QUICType", "[quic]")
IpEndpoint ep;
ats_ip4_set(&ep, 0x04030201, 0x2211);
- uint8_t cid_buf[] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
- 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27};
- QUICConnectionId cid(cid_buf, sizeof(cid_buf));
-
- QUICRetryToken token1(ep, cid);
+ uint8_t cid1_buf[] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27};
+ QUICConnectionId cid1(cid1_buf, sizeof(cid1_buf));
+ uint8_t cid2_buf[] = {0xA0, 0xA1, 0x12, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
+ 0xA9, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7};
+ QUICConnectionId cid2(cid2_buf, sizeof(cid2_buf));
+
+ QUICRetryToken token1(ep, cid1, cid2);
QUICRetryToken token2(token1.buf(), token1.length());
CHECK(token1.is_valid(ep));
@@ -118,6 +121,7 @@ TEST_CASE("QUICType", "[quic]")
CHECK(token1.length() == token2.length());
CHECK(memcmp(token1.buf(), token2.buf(), token1.length()) == 0);
CHECK(token1.original_dcid() == token2.original_dcid());
+ CHECK(token1.scid() == token2.scid());
}
SECTION("QUICResumptionToken")
diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc
index a1bcab3..3539745 100644
--- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc
+++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc
@@ -24,6 +24,7 @@
#include "catch.hpp"
#include "quic/QUICVersionNegotiator.h"
+#include "quic/QUICPacketFactory.h"
#include "quic/QUICPacketProtectionKeyInfo.h"
#include "quic/QUICPacketFactory.h"
#include "quic/Mock.h"
@@ -41,7 +42,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]")
dummy_payload->alloc(iobuffer_size_to_index(dummy_payload_len, BUFFER_SIZE_INDEX_32K));
dummy_payload->fill(dummy_payload_len);
- SECTION("Normal case")
+ SECTION("Match")
{
// Check initial state
CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED);
@@ -60,13 +61,13 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]")
CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED);
}
- SECTION("Negotiation case")
+ SECTION("Unmatch")
{
// Check initial state
CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED);
// Negotiate version
- packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]);
+ packet_factory.set_version(0xff000001);
uint8_t packet_buf[QUICPacket::MAX_INSTANCE_SIZE];
QUICPacketUPtr initial_packet =
packet_factory.create_initial_packet(packet_buf, {}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true);
@@ -76,16 +77,16 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]")
blocks->next = initial_packet->payload_block();
QUICInitialPacketR received_initial_packet(nullptr, {}, {}, blocks, 0);
vn.negotiate(received_initial_packet);
- CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED);
+ CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED);
}
- SECTION("Downgrade case")
+ SECTION("Exercise")
{
// Check initial state
CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED);
// Negotiate version
- packet_factory.set_version(QUIC_EXERCISE_VERSION);
+ packet_factory.set_version(QUIC_EXERCISE_VERSION1);
uint8_t packet_buf[QUICPacket::MAX_INSTANCE_SIZE];
QUICPacketUPtr initial_packet =
packet_factory.create_initial_packet(packet_buf, {}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true);
@@ -125,7 +126,7 @@ TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]")
CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED);
// Negotiate version
- packet_factory.set_version(QUIC_EXERCISE_VERSION);
+ packet_factory.set_version(QUIC_EXERCISE_VERSION1);
uint8_t initial_packet_buf[QUICPacket::MAX_INSTANCE_SIZE];
QUICPacketUPtr packet = packet_factory.create_initial_packet(initial_packet_buf, {}, {}, 0, std::move(dummy_payload),
dummy_payload_len, true, false, true);
@@ -133,8 +134,8 @@ TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]")
QUICInitialPacket &initial_packet = static_cast<QUICInitialPacket &>(*packet);
// Server send VN packet based on Initial packet
- QUICPacketUPtr vn_packet =
- packet_factory.create_version_negotiation_packet(initial_packet.source_cid(), initial_packet.destination_cid());
+ QUICPacketUPtr vn_packet = packet_factory.create_version_negotiation_packet(
+ initial_packet.source_cid(), initial_packet.destination_cid(), QUIC_EXERCISE_VERSION1);
REQUIRE(vn_packet != nullptr);
auto blocks = vn_packet->header_block();
diff --git a/lib/records/RecHttp.cc b/lib/records/RecHttp.cc
index cadb0d9..4a35d29 100644
--- a/lib/records/RecHttp.cc
+++ b/lib/records/RecHttp.cc
@@ -38,39 +38,45 @@ SessionProtocolNameRegistry globalSessionProtocolNameRegistry;
These are also used for NPN setup.
*/
-const char *const TS_ALPN_PROTOCOL_HTTP_0_9 = IP_PROTO_TAG_HTTP_0_9.data();
-const char *const TS_ALPN_PROTOCOL_HTTP_1_0 = IP_PROTO_TAG_HTTP_1_0.data();
-const char *const TS_ALPN_PROTOCOL_HTTP_1_1 = IP_PROTO_TAG_HTTP_1_1.data();
-const char *const TS_ALPN_PROTOCOL_HTTP_2_0 = IP_PROTO_TAG_HTTP_2_0.data();
-const char *const TS_ALPN_PROTOCOL_HTTP_3 = IP_PROTO_TAG_HTTP_3.data();
-const char *const TS_ALPN_PROTOCOL_HTTP_QUIC = IP_PROTO_TAG_HTTP_QUIC.data();
+const char *const TS_ALPN_PROTOCOL_HTTP_0_9 = IP_PROTO_TAG_HTTP_0_9.data();
+const char *const TS_ALPN_PROTOCOL_HTTP_1_0 = IP_PROTO_TAG_HTTP_1_0.data();
+const char *const TS_ALPN_PROTOCOL_HTTP_1_1 = IP_PROTO_TAG_HTTP_1_1.data();
+const char *const TS_ALPN_PROTOCOL_HTTP_2_0 = IP_PROTO_TAG_HTTP_2_0.data();
+const char *const TS_ALPN_PROTOCOL_HTTP_3 = IP_PROTO_TAG_HTTP_3.data();
+const char *const TS_ALPN_PROTOCOL_HTTP_QUIC = IP_PROTO_TAG_HTTP_QUIC.data();
+const char *const TS_ALPN_PROTOCOL_HTTP_3_D27 = IP_PROTO_TAG_HTTP_3_D27.data();
+const char *const TS_ALPN_PROTOCOL_HTTP_QUIC_D27 = IP_PROTO_TAG_HTTP_QUIC_D27.data();
const char *const TS_ALPN_PROTOCOL_GROUP_HTTP = "http";
const char *const TS_ALPN_PROTOCOL_GROUP_HTTP2 = "http2";
-const char *const TS_PROTO_TAG_HTTP_1_0 = TS_ALPN_PROTOCOL_HTTP_1_0;
-const char *const TS_PROTO_TAG_HTTP_1_1 = TS_ALPN_PROTOCOL_HTTP_1_1;
-const char *const TS_PROTO_TAG_HTTP_2_0 = TS_ALPN_PROTOCOL_HTTP_2_0;
-const char *const TS_PROTO_TAG_HTTP_3 = TS_ALPN_PROTOCOL_HTTP_3;
-const char *const TS_PROTO_TAG_HTTP_QUIC = TS_ALPN_PROTOCOL_HTTP_QUIC;
-const char *const TS_PROTO_TAG_TLS_1_3 = IP_PROTO_TAG_TLS_1_3.data();
-const char *const TS_PROTO_TAG_TLS_1_2 = IP_PROTO_TAG_TLS_1_2.data();
-const char *const TS_PROTO_TAG_TLS_1_1 = IP_PROTO_TAG_TLS_1_1.data();
-const char *const TS_PROTO_TAG_TLS_1_0 = IP_PROTO_TAG_TLS_1_0.data();
-const char *const TS_PROTO_TAG_TCP = IP_PROTO_TAG_TCP.data();
-const char *const TS_PROTO_TAG_UDP = IP_PROTO_TAG_UDP.data();
-const char *const TS_PROTO_TAG_IPV4 = IP_PROTO_TAG_IPV4.data();
-const char *const TS_PROTO_TAG_IPV6 = IP_PROTO_TAG_IPV6.data();
+const char *const TS_PROTO_TAG_HTTP_1_0 = TS_ALPN_PROTOCOL_HTTP_1_0;
+const char *const TS_PROTO_TAG_HTTP_1_1 = TS_ALPN_PROTOCOL_HTTP_1_1;
+const char *const TS_PROTO_TAG_HTTP_2_0 = TS_ALPN_PROTOCOL_HTTP_2_0;
+const char *const TS_PROTO_TAG_HTTP_3 = TS_ALPN_PROTOCOL_HTTP_3;
+const char *const TS_PROTO_TAG_HTTP_QUIC = TS_ALPN_PROTOCOL_HTTP_QUIC;
+const char *const TS_PROTO_TAG_HTTP_3_D27 = TS_ALPN_PROTOCOL_HTTP_3_D27;
+const char *const TS_PROTO_TAG_HTTP_QUIC_D27 = TS_ALPN_PROTOCOL_HTTP_QUIC_D27;
+const char *const TS_PROTO_TAG_TLS_1_3 = IP_PROTO_TAG_TLS_1_3.data();
+const char *const TS_PROTO_TAG_TLS_1_2 = IP_PROTO_TAG_TLS_1_2.data();
+const char *const TS_PROTO_TAG_TLS_1_1 = IP_PROTO_TAG_TLS_1_1.data();
+const char *const TS_PROTO_TAG_TLS_1_0 = IP_PROTO_TAG_TLS_1_0.data();
+const char *const TS_PROTO_TAG_TCP = IP_PROTO_TAG_TCP.data();
+const char *const TS_PROTO_TAG_UDP = IP_PROTO_TAG_UDP.data();
+const char *const TS_PROTO_TAG_IPV4 = IP_PROTO_TAG_IPV4.data();
+const char *const TS_PROTO_TAG_IPV6 = IP_PROTO_TAG_IPV6.data();
std::unordered_set<std::string_view> TSProtoTags;
// Precomputed indices for ease of use.
-int TS_ALPN_PROTOCOL_INDEX_HTTP_0_9 = SessionProtocolNameRegistry::INVALID;
-int TS_ALPN_PROTOCOL_INDEX_HTTP_1_0 = SessionProtocolNameRegistry::INVALID;
-int TS_ALPN_PROTOCOL_INDEX_HTTP_1_1 = SessionProtocolNameRegistry::INVALID;
-int TS_ALPN_PROTOCOL_INDEX_HTTP_2_0 = SessionProtocolNameRegistry::INVALID;
-int TS_ALPN_PROTOCOL_INDEX_HTTP_3 = SessionProtocolNameRegistry::INVALID;
-int TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC = SessionProtocolNameRegistry::INVALID;
+int TS_ALPN_PROTOCOL_INDEX_HTTP_0_9 = SessionProtocolNameRegistry::INVALID;
+int TS_ALPN_PROTOCOL_INDEX_HTTP_1_0 = SessionProtocolNameRegistry::INVALID;
+int TS_ALPN_PROTOCOL_INDEX_HTTP_1_1 = SessionProtocolNameRegistry::INVALID;
+int TS_ALPN_PROTOCOL_INDEX_HTTP_2_0 = SessionProtocolNameRegistry::INVALID;
+int TS_ALPN_PROTOCOL_INDEX_HTTP_3 = SessionProtocolNameRegistry::INVALID;
+int TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC = SessionProtocolNameRegistry::INVALID;
+int TS_ALPN_PROTOCOL_INDEX_HTTP_3_D27 = SessionProtocolNameRegistry::INVALID;
+int TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC_D27 = SessionProtocolNameRegistry::INVALID;
// Predefined protocol sets for ease of use.
SessionProtocolSet HTTP_PROTOCOL_SET;
@@ -705,12 +711,15 @@ void
ts_session_protocol_well_known_name_indices_init()
{
// register all the well known protocols and get the indices set.
- TS_ALPN_PROTOCOL_INDEX_HTTP_0_9 = globalSessionProtocolNameRegistry.toIndexConst(std::string_view{TS_ALPN_PROTOCOL_HTTP_0_9});
- TS_ALPN_PROTOCOL_INDEX_HTTP_1_0 = globalSessionProtocolNameRegistry.toIndexConst(std::string_view{TS_ALPN_PROTOCOL_HTTP_1_0});
- TS_ALPN_PROTOCOL_INDEX_HTTP_1_1 = globalSessionProtocolNameRegistry.toIndexConst(std::string_view{TS_ALPN_PROTOCOL_HTTP_1_1});
- TS_ALPN_PROTOCOL_INDEX_HTTP_2_0 = globalSessionProtocolNameRegistry.toIndexConst(std::string_view{TS_ALPN_PROTOCOL_HTTP_2_0});
- TS_ALPN_PROTOCOL_INDEX_HTTP_3 = globalSessionProtocolNameRegistry.toIndexConst(std::string_view{TS_ALPN_PROTOCOL_HTTP_3});
- TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC = globalSessionProtocolNameRegistry.toIndexConst(std::string_view{TS_ALPN_PROTOCOL_HTTP_QUIC});
+ TS_ALPN_PROTOCOL_INDEX_HTTP_0_9 = globalSessionProtocolNameRegistry.toIndexConst(std::string_view{TS_ALPN_PROTOCOL_HTTP_0_9});
+ TS_ALPN_PROTOCOL_INDEX_HTTP_1_0 = globalSessionProtocolNameRegistry.toIndexConst(std::string_view{TS_ALPN_PROTOCOL_HTTP_1_0});
+ TS_ALPN_PROTOCOL_INDEX_HTTP_1_1 = globalSessionProtocolNameRegistry.toIndexConst(std::string_view{TS_ALPN_PROTOCOL_HTTP_1_1});
+ TS_ALPN_PROTOCOL_INDEX_HTTP_2_0 = globalSessionProtocolNameRegistry.toIndexConst(std::string_view{TS_ALPN_PROTOCOL_HTTP_2_0});
+ TS_ALPN_PROTOCOL_INDEX_HTTP_3 = globalSessionProtocolNameRegistry.toIndexConst(std::string_view{TS_ALPN_PROTOCOL_HTTP_3});
+ TS_ALPN_PROTOCOL_INDEX_HTTP_3_D27 = globalSessionProtocolNameRegistry.toIndexConst(std::string_view{TS_ALPN_PROTOCOL_HTTP_3_D27});
+ TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC = globalSessionProtocolNameRegistry.toIndexConst(std::string_view{TS_ALPN_PROTOCOL_HTTP_QUIC});
+ TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC_D27 =
+ globalSessionProtocolNameRegistry.toIndexConst(std::string_view{TS_ALPN_PROTOCOL_HTTP_QUIC_D27});
// Now do the predefined protocol sets.
HTTP_PROTOCOL_SET.markIn(TS_ALPN_PROTOCOL_INDEX_HTTP_0_9);
@@ -724,6 +733,8 @@ ts_session_protocol_well_known_name_indices_init()
DEFAULT_QUIC_SESSION_PROTOCOL_SET.markIn(TS_ALPN_PROTOCOL_INDEX_HTTP_3);
DEFAULT_QUIC_SESSION_PROTOCOL_SET.markIn(TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC);
+ DEFAULT_QUIC_SESSION_PROTOCOL_SET.markIn(TS_ALPN_PROTOCOL_INDEX_HTTP_3_D27);
+ DEFAULT_QUIC_SESSION_PROTOCOL_SET.markIn(TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC_D27);
DEFAULT_NON_TLS_SESSION_PROTOCOL_SET = HTTP_PROTOCOL_SET;
@@ -732,6 +743,8 @@ ts_session_protocol_well_known_name_indices_init()
TSProtoTags.insert(TS_PROTO_TAG_HTTP_2_0);
TSProtoTags.insert(TS_PROTO_TAG_HTTP_3);
TSProtoTags.insert(TS_PROTO_TAG_HTTP_QUIC);
+ TSProtoTags.insert(TS_PROTO_TAG_HTTP_3_D27);
+ TSProtoTags.insert(TS_PROTO_TAG_HTTP_QUIC_D27);
TSProtoTags.insert(TS_PROTO_TAG_TLS_1_3);
TSProtoTags.insert(TS_PROTO_TAG_TLS_1_2);
TSProtoTags.insert(TS_PROTO_TAG_TLS_1_1);
diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc
index cbca682..3ac18d2 100644
--- a/mgmt/RecordsConfig.cc
+++ b/mgmt/RecordsConfig.cc
@@ -1437,9 +1437,9 @@ static const RecordElement RecordsConfig[] =
// Constatns of Congestion Control
{RECT_CONFIG, "proxy.config.quic.congestion_control.max_datagram_size", RECD_INT, "1200", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL}
,
- {RECT_CONFIG, "proxy.config.quic.congestion_control.initial_window_scale", RECD_INT, "10", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL}
+ {RECT_CONFIG, "proxy.config.quic.congestion_control.initial_window", RECD_INT, "12000", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL}
,
- {RECT_CONFIG, "proxy.config.quic.congestion_control.minimum_window_scale", RECD_INT, "2", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL}
+ {RECT_CONFIG, "proxy.config.quic.congestion_control.minimum_window", RECD_INT, "2400", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL}
,
{RECT_CONFIG, "proxy.config.quic.congestion_control.loss_reduction_factor", RECD_FLOAT, "0.5", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[\\.0-9]+$", RECA_NULL}
,
diff --git a/proxy/http/HttpProxyServerMain.cc b/proxy/http/HttpProxyServerMain.cc
index 98941b3..2dbac63 100644
--- a/proxy/http/HttpProxyServerMain.cc
+++ b/proxy/http/HttpProxyServerMain.cc
@@ -238,6 +238,12 @@ MakeHttpProxyAcceptor(HttpProxyAcceptor &acceptor, HttpProxyPort &port, unsigned
quic->enableProtocols(port.m_session_protocol_preference);
+ // HTTP/0.9 over QUIC draft-27 (for interop only, will be removed)
+ quic->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_QUIC_D27, new Http3SessionAccept(accept_opt));
+
+ // HTTP/3 draft-27
+ quic->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_3_D27, new Http3SessionAccept(accept_opt));
+
// HTTP/0.9 over QUIC (for interop only, will be removed)
quic->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_QUIC, new Http3SessionAccept(accept_opt));
diff --git a/proxy/http3/Http3Session.cc b/proxy/http3/Http3Session.cc
index 4d9ceaf..aaea1dfd 100644
--- a/proxy/http3/Http3Session.cc
+++ b/proxy/http3/Http3Session.cc
@@ -29,7 +29,14 @@
//
// HQSession
//
-HQSession ::~HQSession()
+HQSession::HQSession(NetVConnection *vc) : ProxySession(vc)
+{
+ auto app_name = static_cast<QUICNetVConnection *>(vc)->negotiated_application_name();
+ memcpy(this->_protocol_string, app_name.data(), std::min(app_name.length(), sizeof(this->_protocol_string)));
+ this->_protocol_string[app_name.length()] = '\0';
+}
+
+HQSession::~HQSession()
{
for (HQTransaction *t = this->_transaction_list.head; t; t = static_cast<HQTransaction *>(t->link.next)) {
delete t;
@@ -44,6 +51,25 @@ HQSession::add_transaction(HQTransaction *trans)
return;
}
+const char *
+HQSession::get_protocol_string() const
+{
+ return this->_protocol_string;
+}
+
+int
+HQSession::populate_protocol(std::string_view *result, int size) const
+{
+ int retval = 0;
+ if (size > retval) {
+ result[retval++] = this->get_protocol_string();
+ if (size > retval) {
+ retval += super::populate_protocol(result + retval, size - retval);
+ }
+ }
+ return retval;
+}
+
HQTransaction *
HQSession::get_transaction(QUICStreamId id)
{
@@ -143,25 +169,6 @@ Http3Session::~Http3Session()
delete this->_remote_qpack;
}
-const char *
-Http3Session::get_protocol_string() const
-{
- return IP_PROTO_TAG_HTTP_3.data();
-}
-
-int
-Http3Session::populate_protocol(std::string_view *result, int size) const
-{
- int retval = 0;
- if (size > retval) {
- result[retval++] = IP_PROTO_TAG_HTTP_3;
- if (size > retval) {
- retval += super::populate_protocol(result + retval, size - retval);
- }
- }
- return retval;
-}
-
void
Http3Session::increment_current_active_client_connections_stat()
{
@@ -194,25 +201,6 @@ Http09Session::~Http09Session()
this->_vc = nullptr;
}
-const char *
-Http09Session::get_protocol_string() const
-{
- return IP_PROTO_TAG_HTTP_QUIC.data();
-}
-
-int
-Http09Session::populate_protocol(std::string_view *result, int size) const
-{
- int retval = 0;
- if (size > retval) {
- result[retval++] = IP_PROTO_TAG_HTTP_QUIC;
- if (size > retval) {
- retval += super::populate_protocol(result + retval, size - retval);
- }
- }
- return retval;
-}
-
void
Http09Session::increment_current_active_client_connections_stat()
{
diff --git a/proxy/http3/Http3Session.h b/proxy/http3/Http3Session.h
index 6bf5fd2..a6aec41 100644
--- a/proxy/http3/Http3Session.h
+++ b/proxy/http3/Http3Session.h
@@ -32,7 +32,7 @@ class HQSession : public ProxySession
public:
using super = ProxySession; ///< Parent type
- HQSession(NetVConnection *vc) : ProxySession(vc){};
+ HQSession(NetVConnection *vc);
virtual ~HQSession();
// Implement VConnection interface
@@ -43,6 +43,8 @@ public:
void reenable(VIO *vio) override;
// Implement ProxySession interface
+ const char *get_protocol_string() const override;
+ int populate_protocol(std::string_view *result, int size) const override;
void new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reader) override;
void start() override;
void destroy() override;
@@ -56,6 +58,8 @@ public:
private:
// this should be unordered map?
Queue<HQTransaction> _transaction_list;
+
+ char _protocol_string[16];
};
class Http3Session : public HQSession
@@ -67,8 +71,6 @@ public:
~Http3Session();
// ProxySession interface
- const char *get_protocol_string() const override;
- int populate_protocol(std::string_view *result, int size) const override;
void increment_current_active_client_connections_stat() override;
void decrement_current_active_client_connections_stat() override;
@@ -92,8 +94,6 @@ public:
~Http09Session();
// ProxySession interface
- const char *get_protocol_string() const override;
- int populate_protocol(std::string_view *result, int size) const override;
void increment_current_active_client_connections_stat() override;
void decrement_current_active_client_connections_stat() override;
diff --git a/proxy/http3/Http3SessionAccept.cc b/proxy/http3/Http3SessionAccept.cc
index f5d1ff6..93dfbd8 100644
--- a/proxy/http3/Http3SessionAccept.cc
+++ b/proxy/http3/Http3SessionAccept.cc
@@ -62,16 +62,16 @@ Http3SessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferRead
std::string_view alpn = qvc->negotiated_application_name();
- if (alpn.empty() || IP_PROTO_TAG_HTTP_QUIC.compare(alpn) == 0) {
+ if (alpn.empty() || IP_PROTO_TAG_HTTP_QUIC.compare(alpn) == 0 || IP_PROTO_TAG_HTTP_QUIC_D27.compare(alpn) == 0) {
if (alpn.empty()) {
Debug("http3", "[%s] start HTTP/0.9 app (ALPN=null)", qvc->cids().data());
} else {
- Debug("http3", "[%s] start HTTP/0.9 app (ALPN=%s)", qvc->cids().data(), IP_PROTO_TAG_HTTP_QUIC.data());
+ Debug("http3", "[%s] start HTTP/0.9 app (ALPN=%.*s)", qvc->cids().data(), static_cast<int>(alpn.length()), alpn.data());
}
new Http09App(qvc, std::move(session_acl), this->options);
- } else if (IP_PROTO_TAG_HTTP_3.compare(alpn) == 0) {
- Debug("http3", "[%s] start HTTP/3 app (ALPN=%s)", qvc->cids().data(), IP_PROTO_TAG_HTTP_3.data());
+ } else if (IP_PROTO_TAG_HTTP_3.compare(alpn) == 0 || IP_PROTO_TAG_HTTP_3_D27.compare(alpn) == 0) {
+ Debug("http3", "[%s] start HTTP/3 app (ALPN=%.*s)", qvc->cids().data(), static_cast<int>(alpn.length()), alpn.data());
Http3App *app = new Http3App(qvc, std::move(session_acl), this->options);
app->start();
diff --git a/src/traffic_quic/quic_client.cc b/src/traffic_quic/quic_client.cc
index 8a65c28..04fb44d 100644
--- a/src/traffic_quic/quic_client.cc
+++ b/src/traffic_quic/quic_client.cc
@@ -34,8 +34,8 @@
// https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html
// Should be integrate with IP_PROTO_TAG_HTTP_QUIC in ts/ink_inet.h ?
using namespace std::literals;
-static constexpr std::string_view HQ_ALPN_PROTO_LIST("\5hq-27"sv);
-static constexpr std::string_view H3_ALPN_PROTO_LIST("\5h3-27"sv);
+static constexpr std::string_view HQ_ALPN_PROTO_LIST("\5hq-29\5hq-27"sv);
+static constexpr std::string_view H3_ALPN_PROTO_LIST("\5h3-29\5h3-27"sv);
QUICClient::QUICClient(const QUICClientConfig *config) : Continuation(new_ProxyMutex()), _config(config)
{
diff --git a/src/tscore/ink_inet.cc b/src/tscore/ink_inet.cc
index 9d1dff7..6f781cc 100644
--- a/src/tscore/ink_inet.cc
+++ b/src/tscore/ink_inet.cc
@@ -49,9 +49,11 @@ const std::string_view IP_PROTO_TAG_TLS_1_3("tls/1.3"sv);
const std::string_view IP_PROTO_TAG_HTTP_0_9("http/0.9"sv);
const std::string_view IP_PROTO_TAG_HTTP_1_0("http/1.0"sv);
const std::string_view IP_PROTO_TAG_HTTP_1_1("http/1.1"sv);
-const std::string_view IP_PROTO_TAG_HTTP_2_0("h2"sv); // HTTP/2 over TLS
-const std::string_view IP_PROTO_TAG_HTTP_QUIC("hq-27"sv); // HTTP/0.9 over QUIC
-const std::string_view IP_PROTO_TAG_HTTP_3("h3-27"sv); // HTTP/3 over QUIC
+const std::string_view IP_PROTO_TAG_HTTP_2_0("h2"sv); // HTTP/2 over TLS
+const std::string_view IP_PROTO_TAG_HTTP_QUIC("hq-29"sv); // HTTP/0.9 over QUIC
+const std::string_view IP_PROTO_TAG_HTTP_3("h3-29"sv); // HTTP/3 over QUIC
+const std::string_view IP_PROTO_TAG_HTTP_QUIC_D27("hq-27"sv); // HTTP/0.9 over QUIC (draft-27)
+const std::string_view IP_PROTO_TAG_HTTP_3_D27("h3-27"sv); // HTTP/3 over QUIC (draft-27)
const std::string_view UNIX_PROTO_TAG{"unix"sv};