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/07/23 21:24:11 UTC
[trafficserver] 02/03: Squashed commit of the following: (#7000)
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
commit ce9ffb97a228da85482940538f47b60754212653
Author: Masakazu Kitajo <ma...@apache.org>
AuthorDate: Fri Jul 24 04:38:33 2020 +0900
Squashed commit of the following: (#7000)
This merges the QUIC branch up until, and including draft v27.
(cherry picked from commit 18e7cad3fe246f7b5f676a5b7b061d887feb04e4)
---
configure.ac | 21 +-
doc/admin-guide/files/records.config.en.rst | 6 +
iocore/net/P_Net.h | 7 -
iocore/net/P_QUICNet.h | 3 +
iocore/net/P_QUICNetProcessor.h | 2 +
iocore/net/P_QUICNetVConnection.h | 57 +-
iocore/net/P_QUICPacketHandler.h | 14 +-
iocore/net/QUICNet.cc | 3 +-
iocore/net/QUICNetProcessor.cc | 12 +-
iocore/net/QUICNetVConnection.cc | 407 ++--
iocore/net/QUICPacketHandler.cc | 159 +-
iocore/net/quic/Makefile.am | 16 +-
iocore/net/quic/Mock.h | 110 +-
iocore/net/quic/QUICAckFrameCreator.cc | 9 +-
iocore/net/quic/QUICAckFrameCreator.h | 2 +-
iocore/net/quic/QUICAltConnectionManager.cc | 46 +-
iocore/net/quic/QUICAltConnectionManager.h | 7 +-
iocore/net/quic/QUICConfig.cc | 39 +-
iocore/net/quic/QUICConfig.h | 16 +-
iocore/net/quic/QUICCongestionController.h | 13 +
iocore/net/quic/QUICConnection.h | 9 +-
iocore/net/quic/QUICContext.cc | 23 +-
iocore/net/quic/QUICContext.h | 170 +-
iocore/net/quic/QUICDebugNames.cc | 10 +-
iocore/net/quic/QUICEvents.h | 1 +
iocore/net/quic/QUICFlowController.cc | 46 +-
iocore/net/quic/QUICFrame.cc | 180 +-
iocore/net/quic/QUICFrame.h | 115 +-
iocore/net/quic/QUICFrameDispatcher.cc | 7 +-
iocore/net/quic/QUICFrameDispatcher.h | 5 +-
iocore/net/quic/QUICHandshake.cc | 111 +-
iocore/net/quic/QUICHandshake.h | 14 +-
iocore/net/quic/QUICHandshakeProtocol.h | 4 +-
iocore/net/quic/QUICIntUtil.cc | 4 +-
iocore/net/quic/QUICIntUtil.h | 2 +-
iocore/net/quic/QUICKeyGenerator.cc | 8 +-
iocore/net/quic/QUICKeyGenerator.h | 12 +-
iocore/net/quic/QUICKeyGenerator_boringssl.cc | 21 +-
...rator_openssl.cc => QUICKeyGenerator_legacy.cc} | 8 +-
iocore/net/quic/QUICKeyGenerator_openssl.cc | 27 +-
iocore/net/quic/QUICLossDetector.cc | 15 +-
iocore/net/quic/QUICLossDetector.h | 14 +-
iocore/net/quic/QUICNewRenoCongestionController.cc | 8 +-
iocore/net/quic/QUICPacket.cc | 2113 ++++++++++++++------
iocore/net/quic/QUICPacket.h | 698 ++++---
iocore/net/quic/QUICPacketFactory.cc | 397 ++--
iocore/net/quic/QUICPacketFactory.h | 34 +-
iocore/net/quic/QUICPacketHeaderProtector.cc | 43 +-
.../quic/QUICPacketHeaderProtector_boringssl.cc | 31 +-
...nssl.cc => QUICPacketHeaderProtector_legacy.cc} | 0
.../net/quic/QUICPacketHeaderProtector_openssl.cc | 9 +-
iocore/net/quic/QUICPacketPayloadProtector.cc | 124 +-
.../quic/QUICPacketPayloadProtector_boringssl.cc | 131 +-
...ssl.cc => QUICPacketPayloadProtector_legacy.cc} | 8 +-
.../net/quic/QUICPacketPayloadProtector_openssl.cc | 15 +
iocore/net/quic/QUICPacketReceiveQueue.cc | 20 +-
iocore/net/quic/QUICPacketReceiveQueue.h | 3 +-
iocore/net/quic/QUICPathManager.cc | 10 +-
iocore/net/quic/QUICPathManager.h | 20 +-
iocore/net/quic/QUICPinger.cc | 36 +-
iocore/net/quic/QUICPinger.h | 8 +-
iocore/net/quic/QUICResetTokenTable.cc | 53 +
.../net/quic/QUICResetTokenTable.h | 27 +-
iocore/net/quic/QUICRetryIntegrityTag.cc | 79 +
.../{QUICIntUtil.h => QUICRetryIntegrityTag.h} | 24 +-
iocore/net/quic/QUICStream.cc | 2 +-
iocore/net/quic/QUICStreamManager.cc | 42 +-
iocore/net/quic/QUICStreamManager.h | 8 +-
iocore/net/quic/QUICTLS.cc | 323 ++-
iocore/net/quic/QUICTLS.h | 32 +-
iocore/net/quic/QUICTLS_boringssl.cc | 388 +++-
iocore/net/quic/QUICTLS_legacy.cc | 445 +++++
iocore/net/quic/QUICTLS_openssl.cc | 587 +-----
iocore/net/quic/QUICTransportParameters.cc | 85 +-
iocore/net/quic/QUICTransportParameters.h | 5 +-
iocore/net/quic/QUICTypes.cc | 80 +-
iocore/net/quic/QUICTypes.h | 129 +-
iocore/net/quic/QUICVersionNegotiator.cc | 15 +-
iocore/net/quic/qlog/QLog.cc | 103 +
iocore/net/quic/qlog/QLog.h | 145 ++
iocore/net/quic/qlog/QLogEvent.cc | 317 +++
iocore/net/quic/qlog/QLogEvent.h | 1013 ++++++++++
iocore/net/quic/qlog/QLogFrame.cc | 282 +++
iocore/net/quic/qlog/QLogFrame.h | 309 +++
iocore/net/quic/qlog/QLogListener.h | 119 ++
iocore/net/quic/qlog/QLogUtils.h | 80 +
iocore/net/quic/test/main.cc | 2 +
iocore/net/quic/test/test_QUICAckFrameCreator.cc | 23 +
iocore/net/quic/test/test_QUICFrame.cc | 39 +-
iocore/net/quic/test/test_QUICFrameDispatcher.cc | 8 +-
.../net/quic/test/test_QUICFrameRetransmitter.cc | 4 +-
iocore/net/quic/test/test_QUICHandshakeProtocol.cc | 266 ++-
iocore/net/quic/test/test_QUICLossDetector.cc | 141 +-
iocore/net/quic/test/test_QUICPacket.cc | 751 +++++--
iocore/net/quic/test/test_QUICPacketFactory.cc | 69 +-
.../quic/test/test_QUICPacketHeaderProtector.cc | 77 +-
iocore/net/quic/test/test_QUICPathValidator.cc | 2 +-
iocore/net/quic/test/test_QUICPinger.cc | 58 +-
iocore/net/quic/test/test_QUICStream.cc | 13 +-
iocore/net/quic/test/test_QUICStreamManager.cc | 192 +-
iocore/net/quic/test/test_QUICStreamState.cc | 6 +-
.../net/quic/test/test_QUICTransportParameters.cc | 127 +-
iocore/net/quic/test/test_QUICVersionNegotiator.cc | 59 +-
lib/records/RecHttp.cc | 2 +
mgmt/RecordsConfig.cc | 8 +
proxy/http/HttpProxyServerMain.cc | 7 +-
proxy/http/Makefile.am | 3 +-
proxy/http3/Http09App.cc | 1 +
proxy/http3/Http3App.cc | 1 +
proxy/http3/Http3Frame.cc | 4 +-
proxy/http3/Http3HeaderFramer.cc | 2 +-
proxy/http3/Http3Session.cc | 1 +
proxy/http3/Http3SessionAccept.cc | 1 +
proxy/http3/Http3StreamDataVIOAdaptor.cc | 7 +
proxy/http3/Http3StreamDataVIOAdaptor.h | 6 +-
proxy/http3/Http3Transaction.cc | 23 +-
proxy/http3/Http3Transaction.h | 9 +-
proxy/http3/Makefile.am | 3 +-
proxy/http3/test/test_QPACK.cc | 2 +-
src/traffic_quic/Makefile.inc | 2 +-
src/traffic_quic/quic_client.cc | 41 +-
src/traffic_quic/quic_client.h | 5 +-
src/traffic_quic/traffic_quic.cc | 2 +
src/traffic_server/traffic_server.cc | 1 +
src/tscore/ink_inet.cc | 4 +-
125 files changed, 8856 insertions(+), 3271 deletions(-)
diff --git a/configure.ac b/configure.ac
index 92c155a..b07f9a7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1261,18 +1261,31 @@ enable_quic=no
AC_MSG_CHECKING([whether APIs for QUIC are available])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <openssl/ssl.h>]],
[[
- #ifdef OPENSSL_IS_BORINGSSL
SSL_QUIC_METHOD var;
+ ]])
+ ],
+ [
+ AC_MSG_RESULT([yes])
+ enable_quic=yes
+ _quic_saved_LIBS=$LIBS
+ TS_ADDTO(LIBS, [$OPENSSL_LIBS])
+ AC_CHECK_FUNCS(SSL_set_quic_early_data_enabled)
+ LIBS=$_quic_saved_LIBS
+ ],
+ [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <openssl/ssl.h>]],
+ [[
+ #ifdef SSL_MODE_QUIC_HACK
#else
- #ifndef SSL_MODE_QUIC_HACK
# error no hack for quic
#endif
- #endif
]])
],
- [AC_MSG_RESULT([yes]); enable_quic=yes],
+ [AC_MSG_RESULT([yes]); enable_quic=yes; enable_quic_old_api=yes],
[AC_MSG_RESULT([no])])
+ ])
+
AM_CONDITIONAL([ENABLE_QUIC], [test "x$enable_quic" = "xyes"])
+AM_CONDITIONAL([ENABLE_QUIC_OLD_API], [test "x$enable_quic_old_api" = "xyes"])
TS_ARG_ENABLE_VAR([use], [quic])
AC_SUBST(use_quic)
diff --git a/doc/admin-guide/files/records.config.en.rst b/doc/admin-guide/files/records.config.en.rst
index 6e3d9fb..516778f 100644
--- a/doc/admin-guide/files/records.config.en.rst
+++ b/doc/admin-guide/files/records.config.en.rst
@@ -3869,6 +3869,12 @@ QUIC Configuration
All configurations for QUIC are still experimental and may be changed or
removed in the future without prior notice.
+.. ts:cv:: CONFIG proxy.config.quic.qlog_dir STRING NULL
+ :reloadable:
+
+ The qlog is enabled when this configuration is not NULL. And will dump
+ the qlog to this dir.
+
.. ts:cv:: CONFIG proxy.config.quic.instance_id INT 0
:reloadable:
diff --git a/iocore/net/P_Net.h b/iocore/net/P_Net.h
index 46a05c3..b3027ce 100644
--- a/iocore/net/P_Net.h
+++ b/iocore/net/P_Net.h
@@ -111,13 +111,6 @@ extern RecRawStatBlock *net_rsb;
#include "P_SSLNetAccept.h"
#include "P_SSLCertLookup.h"
-#if TS_USE_QUIC == 1
-#include "P_QUICNetVConnection.h"
-#include "P_QUICNetProcessor.h"
-#include "P_QUICPacketHandler.h"
-#include "P_QUICNet.h"
-#endif
-
static constexpr ts::ModuleVersion NET_SYSTEM_MODULE_INTERNAL_VERSION(NET_SYSTEM_MODULE_PUBLIC_VERSION, ts::ModuleVersion::PRIVATE);
// For very verbose iocore debugging.
diff --git a/iocore/net/P_QUICNet.h b/iocore/net/P_QUICNet.h
index 802bf6e..a8a59a2 100644
--- a/iocore/net/P_QUICNet.h
+++ b/iocore/net/P_QUICNet.h
@@ -29,6 +29,9 @@
#include "tscore/ink_platform.h"
#include "P_Net.h"
+#include "quic/QUICTypes.h"
+#include "P_QUICNetProcessor.h"
+#include "P_QUICNetVConnection.h"
class NetHandler;
typedef int (NetHandler::*NetContHandler)(int, void *);
diff --git a/iocore/net/P_QUICNetProcessor.h b/iocore/net/P_QUICNetProcessor.h
index bb3e857..68e7228 100644
--- a/iocore/net/P_QUICNetProcessor.h
+++ b/iocore/net/P_QUICNetProcessor.h
@@ -42,6 +42,7 @@
#include "quic/QUICConnectionTable.h"
class UnixNetVConnection;
+class QUICResetTokenTable;
struct NetAccept;
//////////////////////////////////////////////////////////////////
@@ -73,6 +74,7 @@ private:
QUICNetProcessor &operator=(const QUICNetProcessor &);
QUICConnectionTable *_ctable = nullptr;
+ QUICResetTokenTable *_rtable = nullptr;
};
extern QUICNetProcessor quic_NetProcessor;
diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h
index d39824e..a7aee81 100644
--- a/iocore/net/P_QUICNetVConnection.h
+++ b/iocore/net/P_QUICNetVConnection.h
@@ -37,18 +37,20 @@
#include "P_UnixNetVConnection.h"
#include "P_UnixNet.h"
#include "P_UDPNet.h"
+#include "P_ALPNSupport.h"
+#include "TLSSessionResumptionSupport.h"
#include "tscore/ink_apidefs.h"
#include "tscore/List.h"
#include "quic/QUICConfig.h"
#include "quic/QUICConnection.h"
#include "quic/QUICConnectionTable.h"
+#include "quic/QUICResetTokenTable.h"
#include "quic/QUICVersionNegotiator.h"
#include "quic/QUICPacket.h"
#include "quic/QUICPacketFactory.h"
#include "quic/QUICFrame.h"
#include "quic/QUICFrameDispatcher.h"
-#include "quic/QUICHandshake.h"
#include "quic/QUICApplication.h"
#include "quic/QUICStream.h"
#include "quic/QUICHandshakeProtocol.h"
@@ -62,10 +64,12 @@
#include "quic/QUICPathManager.h"
#include "quic/QUICApplicationMap.h"
#include "quic/QUICPacketReceiveQueue.h"
+#include "quic/QUICPacketHeaderProtector.h"
#include "quic/QUICAddrVerifyState.h"
#include "quic/QUICPacketProtectionKeyInfo.h"
#include "quic/QUICContext.h"
#include "quic/QUICTokenCreator.h"
+#include "quic/qlog/QLogListener.h"
// Size of connection ids for debug log : e.g. aaaaaaaa-bbbbbbbb\0
static constexpr size_t MAX_CIDS_SIZE = 8 + 1 + 8 + 1;
@@ -80,6 +84,7 @@ static constexpr size_t MAX_CIDS_SIZE = 8 + 1 + 8 + 1;
class QUICPacketHandler;
class QUICLossDetector;
+class QUICHandshake;
class SSLNextProtocolSet;
@@ -131,16 +136,21 @@ class SSLNextProtocolSet;
* WRITE:
* Do nothing
**/
-class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, public RefCountObj, public ALPNSupport
+class QUICNetVConnection : public UnixNetVConnection,
+ public QUICConnection,
+ public RefCountObj,
+ public ALPNSupport,
+ public TLSSessionResumptionSupport
{
using super = UnixNetVConnection; ///< Parent type.
public:
QUICNetVConnection();
~QUICNetVConnection();
- void init(QUICConnectionId peer_cid, QUICConnectionId original_cid, UDPConnection *, QUICPacketHandler *);
+ void init(QUICConnectionId peer_cid, QUICConnectionId original_cid, UDPConnection *, QUICPacketHandler *,
+ QUICResetTokenTable *rtable);
void init(QUICConnectionId peer_cid, QUICConnectionId original_cid, QUICConnectionId first_cid, UDPConnection *,
- QUICPacketHandler *, QUICConnectionTable *ctable);
+ QUICPacketHandler *, QUICResetTokenTable *rtable, QUICConnectionTable *ctable);
// accept new conn_id
int acceptEvent(int event, Event *e);
@@ -180,7 +190,8 @@ public:
// QUICConnection
QUICStreamManager *stream_manager() override;
- void close(QUICConnectionErrorUPtr error) override;
+ void close_quic_connection(QUICConnectionErrorUPtr error) override;
+ void reset_quic_connection() override;
void handle_received_packet(UDPPacket *packet) override;
void ping() override;
@@ -207,6 +218,9 @@ public:
LINK(QUICNetVConnection, closed_link);
SLINK(QUICNetVConnection, closed_alink);
+protected:
+ const IpEndpoint &_getLocalEndpoint() override;
+
private:
std::random_device _rnd;
@@ -247,6 +261,7 @@ private:
QUICCongestionController *_congestion_controller = nullptr;
QUICRemoteFlowController *_remote_flow_controller = nullptr;
QUICLocalFlowController *_local_flow_controller = nullptr;
+ QUICResetTokenTable *_rtable = nullptr;
QUICConnectionTable *_ctable = nullptr;
QUICAltConnectionManager *_alt_con_manager = nullptr;
QUICPathValidator *_path_validator = nullptr;
@@ -290,22 +305,23 @@ private:
Ptr<IOBufferBlock> _store_frame(Ptr<IOBufferBlock> parent_block, size_t &size_added, uint64_t &max_frame_size, QUICFrame &frame,
std::vector<QUICFrameInfo> &frames);
- QUICPacketUPtr _packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size, std::vector<QUICFrameInfo> &frames);
+ QUICPacketUPtr _packetize_frames(uint8_t *packet_buf, QUICEncryptionLevel level, uint64_t max_packet_size,
+ std::vector<QUICFrameInfo> &frames);
void _packetize_closing_frame();
- QUICPacketUPtr _build_packet(QUICEncryptionLevel level, Ptr<IOBufferBlock> parent_block, bool retransmittable, bool probing,
- bool crypto);
+ QUICPacketUPtr _build_packet(uint8_t *packet_buf, QUICEncryptionLevel level, Ptr<IOBufferBlock> parent_block,
+ bool retransmittable, bool probing, bool crypto);
- QUICConnectionErrorUPtr _recv_and_ack(const QUICPacket &packet, bool *has_non_probing_frame = nullptr);
+ QUICConnectionErrorUPtr _recv_and_ack(const QUICPacketR &packet, bool *has_non_probing_frame = nullptr);
QUICConnectionErrorUPtr _state_handshake_process_packet(const QUICPacket &packet);
- QUICConnectionErrorUPtr _state_handshake_process_version_negotiation_packet(const QUICPacket &packet);
- QUICConnectionErrorUPtr _state_handshake_process_initial_packet(const QUICPacket &packet);
- QUICConnectionErrorUPtr _state_handshake_process_retry_packet(const QUICPacket &packet);
- QUICConnectionErrorUPtr _state_handshake_process_handshake_packet(const QUICPacket &packet);
- QUICConnectionErrorUPtr _state_handshake_process_zero_rtt_protected_packet(const QUICPacket &packet);
+ QUICConnectionErrorUPtr _state_handshake_process_version_negotiation_packet(const QUICVersionNegotiationPacketR &packet);
+ QUICConnectionErrorUPtr _state_handshake_process_initial_packet(const QUICInitialPacketR &packet);
+ QUICConnectionErrorUPtr _state_handshake_process_retry_packet(const QUICRetryPacketR &packet);
+ QUICConnectionErrorUPtr _state_handshake_process_handshake_packet(const QUICHandshakePacketR &packet);
+ QUICConnectionErrorUPtr _state_handshake_process_zero_rtt_protected_packet(const QUICZeroRttPacketR &packet);
QUICConnectionErrorUPtr _state_connection_established_receive_packet();
- QUICConnectionErrorUPtr _state_connection_established_process_protected_packet(const QUICPacket &packet);
- QUICConnectionErrorUPtr _state_connection_established_migrate_connection(const QUICPacket &packet);
+ QUICConnectionErrorUPtr _state_connection_established_process_protected_packet(const QUICShortHeaderPacketR &packet);
+ QUICConnectionErrorUPtr _state_connection_established_migrate_connection(const QUICPacketR &packet);
QUICConnectionErrorUPtr _state_connection_established_initiate_connection_migration();
QUICConnectionErrorUPtr _state_closing_receive_packet();
QUICConnectionErrorUPtr _state_draining_receive_packet();
@@ -318,7 +334,7 @@ private:
void _init_flow_control_params(const std::shared_ptr<const QUICTransportParameters> &local_tp,
const std::shared_ptr<const QUICTransportParameters> &remote_tp);
void _handle_error(QUICConnectionErrorUPtr error);
- QUICPacketUPtr _dequeue_recv_packet(QUICPacketCreationResult &result);
+ QUICPacketUPtr _dequeue_recv_packet(uint8_t *packet_buf, QUICPacketCreationResult &result);
void _validate_new_path(const QUICPath &path);
int _complete_handshake_if_possible();
@@ -344,6 +360,7 @@ private:
QUICHandshakeProtocol *_setup_handshake_protocol(shared_SSL_CTX ctx);
QUICPacketUPtr _the_final_packet = QUICPacketFactory::create_null_packet();
+ uint8_t _final_packet_buf[QUICPacket::MAX_INSTANCE_SIZE];
QUICStatelessResetToken _reset_token;
ats_unique_buf _av_token = {nullptr};
@@ -353,9 +370,11 @@ private:
uint32_t _seq_num = 0;
// TODO: Source addresses verification through an address validation token
- QUICAddrVerifyState _verfied_state;
+ QUICAddrVerifyState _verified_state;
+
+ std::unique_ptr<QUICContext> _context;
- std::unique_ptr<QUICContextImpl> _context;
+ std::shared_ptr<QLog::QLogListener> _qlog;
};
typedef int (QUICNetVConnection::*QUICNetVConnHandler)(int, void *);
diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h
index 27a5235..4df92ec 100644
--- a/iocore/net/P_QUICPacketHandler.h
+++ b/iocore/net/P_QUICPacketHandler.h
@@ -28,6 +28,7 @@
#include "P_NetAccept.h"
#include "quic/QUICTypes.h"
#include "quic/QUICConnectionTable.h"
+#include "quic/QUICResetTokenTable.h"
class QUICClosedConCollector;
class QUICNetVConnection;
@@ -37,7 +38,7 @@ class QUICPacketHeaderProtector;
class QUICPacketHandler
{
public:
- QUICPacketHandler();
+ QUICPacketHandler(QUICResetTokenTable &rtable);
~QUICPacketHandler();
void send_packet(const QUICPacket &packet, QUICNetVConnection *vc, const QUICPacketHeaderProtector &pn_protector);
@@ -49,6 +50,7 @@ protected:
void _send_packet(const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu,
const QUICPacketHeaderProtector *ph_protector, int dcil);
void _send_packet(UDPConnection *udp_con, IpEndpoint &addr, Ptr<IOBufferBlock> udp_payload);
+ QUICConnection *_check_stateless_reset(const uint8_t *buf, size_t buf_len);
// FIXME Remove this
// QUICPacketHandler could be a continuation, but NetAccept is a contination too.
@@ -58,6 +60,8 @@ protected:
QUICClosedConCollector *_closed_con_collector = nullptr;
virtual void _recv_packet(int event, UDPPacket *udpPacket) = 0;
+
+ QUICResetTokenTable &_rtable;
};
/*
@@ -67,7 +71,7 @@ protected:
class QUICPacketHandlerIn : public NetAccept, public QUICPacketHandler
{
public:
- QUICPacketHandlerIn(const NetProcessor::AcceptOptions &opt, QUICConnectionTable &ctable);
+ QUICPacketHandlerIn(const NetProcessor::AcceptOptions &opt, QUICConnectionTable &ctable, QUICResetTokenTable &rtable);
~QUICPacketHandlerIn();
// NetAccept
@@ -84,6 +88,10 @@ 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);
+ 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,
+ IpEndpoint from);
QUICConnectionTable &_ctable;
};
@@ -95,7 +103,7 @@ private:
class QUICPacketHandlerOut : public Continuation, public QUICPacketHandler
{
public:
- QUICPacketHandlerOut();
+ QUICPacketHandlerOut(QUICResetTokenTable &rtable);
~QUICPacketHandlerOut(){};
void init(QUICNetVConnection *vc);
diff --git a/iocore/net/QUICNet.cc b/iocore/net/QUICNet.cc
index d3df166..34e21ae 100644
--- a/iocore/net/QUICNet.cc
+++ b/iocore/net/QUICNet.cc
@@ -22,6 +22,7 @@
*/
#include "P_Net.h"
+#include "P_QUICNet.h"
#include "quic/QUICEvents.h"
ClassAllocator<QUICPollEvent> quicPollEventAllocator("quicPollEvent");
@@ -68,7 +69,7 @@ QUICPollCont::_process_long_header_packet(QUICPollEvent *e, NetHandler *nh)
uint8_t *buf = (uint8_t *)p->getIOBlockChain()->buf();
QUICPacketType ptype;
- QUICPacketLongHeader::type(ptype, buf, 1);
+ QUICLongHeaderPacketR::type(ptype, buf, 1);
if (ptype == QUICPacketType::INITIAL && !vc->read.triggered) {
SCOPED_MUTEX_LOCK(lock, vc->mutex, this_ethread());
vc->read.triggered = 1;
diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc
index a0c706a..4dfebae 100644
--- a/iocore/net/QUICNetProcessor.cc
+++ b/iocore/net/QUICNetProcessor.cc
@@ -25,9 +25,13 @@
#include "P_Net.h"
#include "records/I_RecHttp.h"
+#include "P_QUICNetProcessor.h"
+#include "P_QUICNet.h"
+#include "P_QUICPacketHandler.h"
#include "QUICGlobals.h"
#include "QUICConfig.h"
#include "QUICMultiCertConfigLoader.h"
+#include "QUICResetTokenTable.h"
//
// Global Data
@@ -76,8 +80,9 @@ QUICNetProcessor::createNetAccept(const NetProcessor::AcceptOptions &opt)
if (this->_ctable == nullptr) {
QUICConfig::scoped_config params;
this->_ctable = new QUICConnectionTable(params->connection_table_size());
+ this->_rtable = new QUICResetTokenTable();
}
- return (NetAccept *)new QUICPacketHandlerIn(opt, *this->_ctable);
+ return (NetAccept *)new QUICPacketHandlerIn(opt, *this->_ctable, *this->_rtable);
}
NetVConnection *
@@ -125,7 +130,8 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, Ne
UnixUDPConnection *con = new UnixUDPConnection(fd);
Debug("quic_ps", "con=%p fd=%d", con, fd);
- QUICPacketHandlerOut *packet_handler = new QUICPacketHandlerOut();
+ this->_rtable = new QUICResetTokenTable();
+ QUICPacketHandlerOut *packet_handler = new QUICPacketHandlerOut(*this->_rtable);
if (opt->local_ip.isValid()) {
con->setBinding(opt->local_ip, opt->local_port);
}
@@ -144,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);
+ vc->init(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 004867d..8338753 100644
--- a/iocore/net/QUICNetVConnection.cc
+++ b/iocore/net/QUICNetVConnection.cc
@@ -27,6 +27,8 @@
#include "records/I_RecHttp.h"
#include "tscore/Diags.h"
+#include "P_QUICNetVConnection.h"
+#include "P_QUICPacketHandler.h"
#include "P_Net.h"
#include "InkAPIInternal.h" // Added to include the quic_hook definitions
#include "Log.h"
@@ -39,12 +41,16 @@
#include "QUICGlobals.h"
#include "QUICDebugNames.h"
#include "QUICEvents.h"
+#include "QUICHandshake.h"
#include "QUICConfig.h"
#include "QUICIntUtil.h"
using namespace std::literals;
static constexpr std::string_view QUIC_DEBUG_TAG = "quic_net"sv;
+static constexpr uint16_t QUANTUM_TEST_ID = 3127;
+static constexpr uint8_t QUANTUM_TEST_VALUE[1200] = {'Q'};
+
#define QUICConDebug(fmt, ...) Debug(QUIC_DEBUG_TAG.data(), "[%s] " fmt, this->cids().data(), ##__VA_ARGS__)
#define QUICConVDebug(fmt, ...) Debug("v_quic_net", "[%s] " fmt, this->cids().data(), ##__VA_ARGS__)
@@ -188,9 +194,33 @@ public:
}
}
+ bool
+ disable_active_migration() const override
+ {
+ if (this->_ctx == NET_VCONNECTION_IN) {
+ return this->_params->disable_active_migration();
+ } else {
+ return false;
+ }
+ }
+
+ std::unordered_map<uint16_t, std::pair<const uint8_t *, uint16_t>>
+ additional_tp() const override
+ {
+ return this->_additional_tp;
+ }
+
+ void
+ add_tp(uint16_t id, const uint8_t *value, uint16_t length)
+ {
+ this->_additional_tp.emplace(std::piecewise_construct, std::forward_as_tuple(id), std::forward_as_tuple(value, length));
+ }
+
private:
const QUICConfigParams *_params;
NetVConnectionContext_t _ctx;
+
+ std::unordered_map<uint16_t, std::pair<const uint8_t *, uint16_t>> _additional_tp;
};
QUICNetVConnection::QUICNetVConnection() : _packet_factory(this->_pp_key_info), _ph_protector(this->_pp_key_info) {}
@@ -207,31 +237,28 @@ QUICNetVConnection::~QUICNetVConnection()
// Initialize QUICNetVC for out going connection (NET_VCONNECTION_OUT)
void
QUICNetVConnection::init(QUICConnectionId peer_cid, QUICConnectionId original_cid, UDPConnection *udp_con,
- QUICPacketHandler *packet_handler)
+ QUICPacketHandler *packet_handler, QUICResetTokenTable *rtable)
{
SET_HANDLER((NetVConnHandler)&QUICNetVConnection::startEvent);
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->_update_cids();
if (is_debug_tag_set(QUIC_DEBUG_TAG.data())) {
- char dcid_hex_str[QUICConnectionId::MAX_HEX_STR_LENGTH];
- char scid_hex_str[QUICConnectionId::MAX_HEX_STR_LENGTH];
- this->_peer_quic_connection_id.hex(dcid_hex_str, QUICConnectionId::MAX_HEX_STR_LENGTH);
- this->_quic_connection_id.hex(scid_hex_str, QUICConnectionId::MAX_HEX_STR_LENGTH);
-
- QUICConDebug("dcid=%s scid=%s", dcid_hex_str, scid_hex_str);
+ QUICConDebug("dcid=%s scid=%s", this->_peer_quic_connection_id.hex().c_str(), this->_quic_connection_id.hex().c_str());
}
}
// 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, QUICConnectionTable *ctable)
+ UDPConnection *udp_con, QUICPacketHandler *packet_handler, QUICResetTokenTable *rtable,
+ QUICConnectionTable *ctable)
{
SET_HANDLER((NetVConnHandler)&QUICNetVConnection::acceptEvent);
this->_udp_con = udp_con;
@@ -246,16 +273,12 @@ QUICNetVConnection::init(QUICConnectionId peer_cid, QUICConnectionId original_ci
this->_ctable->insert(this->_quic_connection_id, this);
this->_ctable->insert(this->_original_quic_connection_id, this);
}
+ this->_rtable = rtable;
this->_update_cids();
if (is_debug_tag_set(QUIC_DEBUG_TAG.data())) {
- char dcid_hex_str[QUICConnectionId::MAX_HEX_STR_LENGTH];
- char scid_hex_str[QUICConnectionId::MAX_HEX_STR_LENGTH];
- this->_peer_quic_connection_id.hex(dcid_hex_str, QUICConnectionId::MAX_HEX_STR_LENGTH);
- this->_quic_connection_id.hex(scid_hex_str, QUICConnectionId::MAX_HEX_STR_LENGTH);
-
- QUICConDebug("dcid=%s scid=%s", dcid_hex_str, scid_hex_str);
+ QUICConDebug("dcid=%s scid=%s", this->_peer_quic_connection_id.hex().c_str(), this->_quic_connection_id.hex().c_str());
}
}
@@ -356,7 +379,17 @@ void
QUICNetVConnection::start()
{
ink_release_assert(this->thread != nullptr);
- this->_context = std::make_unique<QUICContextImpl>(&this->_rtt_measure, this, &this->_pp_key_info);
+ 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
@@ -374,6 +407,9 @@ QUICNetVConnection::start()
} else {
trusted_path = {this->local_addr, this->remote_addr};
QUICTPConfigQCP tp_config(this->_quic_config, NET_VCONNECTION_OUT);
+ if (this->_quic_config->quantum_readiness_test_enabled_out()) {
+ tp_config.add_tp(QUANTUM_TEST_ID, QUANTUM_TEST_VALUE, sizeof(QUANTUM_TEST_VALUE));
+ }
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());
@@ -383,6 +419,7 @@ QUICNetVConnection::start()
this->_ack_frame_manager.set_max_ack_delay(this->_quic_config->max_ack_delay_out());
this->_schedule_ack_manager_periodic(this->_quic_config->max_ack_delay_out());
}
+ this->_path_manager->set_trusted_path(trusted_path);
this->_application_map = new QUICApplicationMap();
@@ -399,19 +436,8 @@ QUICNetVConnection::start()
this->_remote_flow_controller = new QUICRemoteConnectionFlowController(UINT64_MAX);
this->_local_flow_controller = new QUICLocalConnectionFlowController(&this->_rtt_measure, UINT64_MAX);
- 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->_stream_manager = new QUICStreamManager(this, &this->_rtt_measure, this->_application_map);
- this->_path_manager = new QUICPathManager(*this, *this->_path_validator);
- this->_path_manager->set_trusted_path(trusted_path);
- this->_token_creator = new QUICTokenCreator(this->_context.get());
+ this->_stream_manager = new QUICStreamManager(this->_context.get(), this->_application_map);
+ this->_token_creator = new QUICTokenCreator(this->_context.get());
static constexpr int QUIC_STREAM_MANAGER_WEIGHT = QUICFrameGeneratorWeight::AFTER_DATA - 1;
static constexpr int QUIC_PINGER_WEIGHT = QUICFrameGeneratorWeight::LATE + 1;
@@ -436,6 +462,14 @@ QUICNetVConnection::start()
this->_frame_dispatcher->add_handler(this->_stream_manager);
this->_frame_dispatcher->add_handler(this->_path_validator);
this->_frame_dispatcher->add_handler(this->_handshake_handler);
+
+ // regist qlog
+ if (this->_context->config()->qlog_dir() != nullptr) {
+ this->_qlog = std::make_unique<QLog::QLogListener>(*this->_context, this->_original_quic_connection_id.hex());
+ this->_qlog->last_trace().set_vantage_point(
+ {"ats", QLog::Trace::VantagePointType::server, QLog::Trace::VantagePointType::server});
+ this->_context->regist_callback(this->_qlog);
+ }
}
void
@@ -462,6 +496,7 @@ QUICNetVConnection::free(EThread *t)
super::clear();
*/
+ this->_context->trigger(QUICContext::CallbackEvent::CONNECTION_CLOSE);
ALPNSupport::clear();
this->_packet_handler->close_connection(this);
}
@@ -641,11 +676,11 @@ QUICNetVConnection::handle_received_packet(UDPPacket *packet)
void
QUICNetVConnection::ping()
{
- this->_pinger->request();
+ this->_pinger->request(QUICEncryptionLevel::ONE_RTT);
}
void
-QUICNetVConnection::close(QUICConnectionErrorUPtr error)
+QUICNetVConnection::close_quic_connection(QUICConnectionErrorUPtr error)
{
if (this->handler == reinterpret_cast<ContinuationHandler>(&QUICNetVConnection::state_connection_closed) ||
this->handler == reinterpret_cast<ContinuationHandler>(&QUICNetVConnection::state_connection_closing)) {
@@ -655,6 +690,24 @@ QUICNetVConnection::close(QUICConnectionErrorUPtr error)
}
}
+void
+QUICNetVConnection::reset_quic_connection()
+{
+ this->_switch_to_close_state();
+
+ QUICStatelessResetToken token(this->connection_id(), this->_quic_config->instance_id());
+ auto packet = QUICPacketFactory::create_stateless_reset_packet(token, 128);
+ if (packet) {
+ Ptr<IOBufferBlock> udp_payload(new_IOBufferBlock());
+ udp_payload->alloc(iobuffer_size_to_index(128, BUFFER_SIZE_INDEX_32K));
+ uint8_t *buf = reinterpret_cast<uint8_t *>(udp_payload->end());
+ size_t len = 0;
+ packet->store(buf, &len);
+ udp_payload->fill(len);
+ this->_packet_handler->send_packet(this, udp_payload);
+ }
+}
+
std::vector<QUICFrameType>
QUICNetVConnection::interests()
{
@@ -745,7 +798,8 @@ QUICNetVConnection::state_handshake(int event, Event *data)
QUICPacketCreationResult result;
net_activity(this, this_ethread());
do {
- QUICPacketUPtr packet = this->_dequeue_recv_packet(result);
+ uint8_t packet_buf[QUICPacket::MAX_INSTANCE_SIZE];
+ QUICPacketUPtr packet = this->_dequeue_recv_packet(packet_buf, result);
if (result == QUICPacketCreationResult::NOT_READY) {
error = nullptr;
} else if (result == QUICPacketCreationResult::FAILED) {
@@ -767,6 +821,9 @@ QUICNetVConnection::state_handshake(int event, Event *data)
} while (error == nullptr && (result == QUICPacketCreationResult::SUCCESS || result == QUICPacketCreationResult::IGNORED));
break;
}
+ case QUIC_EVENT_STATELESS_RESET:
+ this->_switch_to_draining_state(std::make_unique<QUICConnectionError>(QUICTransErrorCode::NO_ERROR, "Stateless Reset"));
+ break;
case QUIC_EVENT_ACK_PERIODIC:
this->_handle_periodic_ack_event();
break;
@@ -810,6 +867,9 @@ QUICNetVConnection::state_connection_established(int event, Event *data)
// Reschedule WRITE_READY
this->_schedule_packet_write_ready(true);
break;
+ case QUIC_EVENT_STATELESS_RESET:
+ this->_switch_to_draining_state(std::make_unique<QUICConnectionError>(QUICTransErrorCode::NO_ERROR, "Stateless Reset"));
+ break;
case VC_EVENT_INACTIVITY_TIMEOUT:
// Start Immediate Close because of Idle Timeout
this->_handle_idle_timeout();
@@ -844,6 +904,8 @@ QUICNetVConnection::state_connection_closing(int event, Event *data)
this->_close_closing_timeout(data);
this->_switch_to_close_state();
break;
+ case QUIC_EVENT_STATELESS_RESET:
+ break;
case QUIC_EVENT_ACK_PERIODIC:
default:
QUICConDebug("Unexpected event: %s (%d)", QUICDebugNames::quic_event(event), event);
@@ -872,6 +934,8 @@ QUICNetVConnection::state_connection_draining(int event, Event *data)
this->_close_closing_timeout(data);
this->_switch_to_close_state();
break;
+ case QUIC_EVENT_STATELESS_RESET:
+ break;
case QUIC_EVENT_ACK_PERIODIC:
default:
QUICConDebug("Unexpected event: %s (%d)", QUICDebugNames::quic_event(event), event);
@@ -1024,28 +1088,28 @@ QUICNetVConnection::_state_handshake_process_packet(const QUICPacket &packet)
QUICConnectionErrorUPtr error = nullptr;
switch (packet.type()) {
case QUICPacketType::VERSION_NEGOTIATION:
- error = this->_state_handshake_process_version_negotiation_packet(packet);
+ error = this->_state_handshake_process_version_negotiation_packet(static_cast<const QUICVersionNegotiationPacketR &>(packet));
break;
case QUICPacketType::INITIAL:
- error = this->_state_handshake_process_initial_packet(packet);
+ error = this->_state_handshake_process_initial_packet(static_cast<const QUICInitialPacketR &>(packet));
break;
case QUICPacketType::RETRY:
- error = this->_state_handshake_process_retry_packet(packet);
+ error = this->_state_handshake_process_retry_packet(static_cast<const QUICRetryPacketR &>(packet));
break;
case QUICPacketType::HANDSHAKE:
- error = this->_state_handshake_process_handshake_packet(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->_minimum_encryption_level = QUICEncryptionLevel::HANDSHAKE;
}
break;
case QUICPacketType::ZERO_RTT_PROTECTED:
- error = this->_state_handshake_process_zero_rtt_protected_packet(packet);
+ error = this->_state_handshake_process_zero_rtt_protected_packet(static_cast<const QUICZeroRttPacketR &>(packet));
break;
case QUICPacketType::PROTECTED:
- default:
QUICConDebug("Ignore %s(%" PRIu8 ") packet", QUICDebugNames::packet_type(packet.type()), static_cast<uint8_t>(packet.type()));
-
+ break;
+ default:
error = std::make_unique<QUICConnectionError>(QUICTransErrorCode::INTERNAL_ERROR);
break;
}
@@ -1053,7 +1117,7 @@ QUICNetVConnection::_state_handshake_process_packet(const QUICPacket &packet)
}
QUICConnectionErrorUPtr
-QUICNetVConnection::_state_handshake_process_version_negotiation_packet(const QUICPacket &packet)
+QUICNetVConnection::_state_handshake_process_version_negotiation_packet(const QUICVersionNegotiationPacketR &packet)
{
QUICConnectionErrorUPtr error = nullptr;
@@ -1082,7 +1146,7 @@ QUICNetVConnection::_state_handshake_process_version_negotiation_packet(const QU
}
QUICConnectionErrorUPtr
-QUICNetVConnection::_state_handshake_process_initial_packet(const QUICPacket &packet)
+QUICNetVConnection::_state_handshake_process_initial_packet(const QUICInitialPacketR &packet)
{
// QUIC packet could be smaller than MINIMUM_INITIAL_PACKET_SIZE when coalescing packets
// if (packet->size() < MINIMUM_INITIAL_PACKET_SIZE) {
@@ -1101,28 +1165,31 @@ QUICNetVConnection::_state_handshake_process_initial_packet(const QUICPacket &pa
if (!this->_alt_con_manager) {
this->_alt_con_manager =
- new QUICAltConnectionManager(this, *this->_ctable, this->_peer_quic_connection_id, this->_quic_config->instance_id(),
- this->_quic_config->active_cid_limit_in(), this->_quic_config->preferred_address_ipv4(),
- this->_quic_config->preferred_address_ipv6());
+ new QUICAltConnectionManager(this, *this->_ctable, *this->_rtable, this->_peer_quic_connection_id,
+ this->_quic_config->instance_id(), this->_quic_config->active_cid_limit_in(),
+ this->_quic_config->preferred_address_ipv4(), this->_quic_config->preferred_address_ipv6());
this->_frame_generators.add_generator(*this->_alt_con_manager, QUICFrameGeneratorWeight::EARLY);
this->_frame_dispatcher->add_handler(this->_alt_con_manager);
}
QUICTPConfigQCP tp_config(this->_quic_config, NET_VCONNECTION_IN);
+ if (this->_quic_config->quantum_readiness_test_enabled_in()) {
+ tp_config.add_tp(QUANTUM_TEST_ID, QUANTUM_TEST_VALUE, sizeof(QUANTUM_TEST_VALUE));
+ }
error = this->_handshake_handler->start(tp_config, packet, &this->_packet_factory, this->_alt_con_manager->preferred_address());
// If version negotiation was failed and VERSION NEGOTIATION packet was sent, nothing to do.
if (this->_handshake_handler->is_version_negotiated()) {
error = this->_recv_and_ack(packet);
- if (error == nullptr && !this->_handshake_handler->has_remote_tp()) {
+ if (error == nullptr && this->_handshake_handler->is_completed() && !this->_handshake_handler->has_remote_tp()) {
error = std::make_unique<QUICConnectionError>(QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR);
}
}
} else {
if (!this->_alt_con_manager) {
this->_alt_con_manager =
- new QUICAltConnectionManager(this, *this->_ctable, this->_peer_quic_connection_id, this->_quic_config->instance_id(),
- this->_quic_config->active_cid_limit_out());
+ new QUICAltConnectionManager(this, *this->_ctable, *this->_rtable, this->_peer_quic_connection_id,
+ this->_quic_config->instance_id(), this->_quic_config->active_cid_limit_out());
this->_frame_generators.add_generator(*this->_alt_con_manager, QUICFrameGeneratorWeight::BEFORE_DATA);
this->_frame_dispatcher->add_handler(this->_alt_con_manager);
}
@@ -1138,7 +1205,7 @@ QUICNetVConnection::_state_handshake_process_initial_packet(const QUICPacket &pa
This doesn't call this->_recv_and_ack(), because RETRY packet doesn't have any frames.
*/
QUICConnectionErrorUPtr
-QUICNetVConnection::_state_handshake_process_retry_packet(const QUICPacket &packet)
+QUICNetVConnection::_state_handshake_process_retry_packet(const QUICRetryPacketR &packet)
{
ink_assert(this->netvc_context == NET_VCONNECTION_OUT);
@@ -1147,10 +1214,19 @@ QUICNetVConnection::_state_handshake_process_retry_packet(const QUICPacket &pack
return nullptr;
}
+ // Check Integrity Tag
+ if (!packet.has_valid_tag(this->_original_quic_connection_id)) {
+ // Discard the packet
+ QUICConDebug("Ignore RETRY packet - integrity tag is not valid");
+ return nullptr;
+ } else {
+ QUICConDebug("Integrity tag is valid");
+ }
+
// TODO: move packet->payload to _av_token
- this->_av_token_len = packet.payload_length();
+ this->_av_token_len = packet.token().length();
this->_av_token = ats_unique_malloc(this->_av_token_len);
- memcpy(this->_av_token.get(), packet.payload(), this->_av_token_len);
+ memcpy(this->_av_token.get(), packet.token().buf(), this->_av_token_len);
this->_padder->set_av_token_len(this->_av_token_len);
@@ -1174,18 +1250,18 @@ QUICNetVConnection::_state_handshake_process_retry_packet(const QUICPacket &pack
}
QUICConnectionErrorUPtr
-QUICNetVConnection::_state_handshake_process_handshake_packet(const QUICPacket &packet)
+QUICNetVConnection::_state_handshake_process_handshake_packet(const QUICHandshakePacketR &packet)
{
// Source address is verified by receiving any message from the client encrypted using the
// Handshake keys.
- if (this->netvc_context == NET_VCONNECTION_IN && !this->_verfied_state.is_verified()) {
- this->_verfied_state.set_addr_verifed();
+ if (this->netvc_context == NET_VCONNECTION_IN && !this->_verified_state.is_verified()) {
+ this->_verified_state.set_addr_verifed();
}
return this->_recv_and_ack(packet);
}
QUICConnectionErrorUPtr
-QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(const QUICPacket &packet)
+QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(const QUICZeroRttPacketR &packet)
{
this->_stream_manager->init_flow_control_params(this->_handshake_handler->local_transport_parameters(),
this->_handshake_handler->remote_transport_parameters());
@@ -1194,7 +1270,7 @@ QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(const QUI
}
QUICConnectionErrorUPtr
-QUICNetVConnection::_state_connection_established_process_protected_packet(const QUICPacket &packet)
+QUICNetVConnection::_state_connection_established_process_protected_packet(const QUICShortHeaderPacketR &packet)
{
QUICConnectionErrorUPtr error = nullptr;
bool has_non_probing_frame = false;
@@ -1204,16 +1280,10 @@ QUICNetVConnection::_state_connection_established_process_protected_packet(const
return error;
}
- // Migrate connection if required
- // FIXME Connection migration will be initiated when a peer sent non-probing frames.
- // We need to two or more paths because we need to respond to probing packets on a new path and also need to send other frames
- // on the old path until they initiate migration.
- // if (packet.destination_cid() == this->_quic_connection_id && has_non_probing_frame) {
+ // Migrate connection if needed
if (this->_alt_con_manager != nullptr) {
- if (packet.destination_cid() != this->_quic_connection_id || !ats_ip_addr_port_eq(packet.from(), this->remote_addr)) {
- if (!has_non_probing_frame) {
- QUICConDebug("FIXME: Connection migration has been initiated without non-probing frames");
- }
+ if (has_non_probing_frame &&
+ (packet.destination_cid() != this->_quic_connection_id || !ats_ip_addr_port_eq(packet.from(), this->remote_addr))) {
error = this->_state_connection_established_migrate_connection(packet);
if (error != nullptr) {
return error;
@@ -1238,7 +1308,8 @@ QUICNetVConnection::_state_connection_established_receive_packet()
// Receive a QUIC packet
net_activity(this, this_ethread());
do {
- QUICPacketUPtr packet = this->_dequeue_recv_packet(result);
+ uint8_t packet_buf[QUICPacket::MAX_INSTANCE_SIZE];
+ QUICPacketUPtr packet = this->_dequeue_recv_packet(packet_buf, result);
if (result == QUICPacketCreationResult::FAILED) {
// Don't make this error, and discard the packet.
// Because:
@@ -1256,13 +1327,13 @@ QUICNetVConnection::_state_connection_established_receive_packet()
// Process the packet
switch (packet->type()) {
case QUICPacketType::PROTECTED:
- error = this->_state_connection_established_process_protected_packet(*packet);
+ error = this->_state_connection_established_process_protected_packet(static_cast<QUICShortHeaderPacketR &>(*packet));
break;
case QUICPacketType::INITIAL:
case QUICPacketType::HANDSHAKE:
case QUICPacketType::ZERO_RTT_PROTECTED:
// Pass packet to _recv_and_ack to send ack to the packet. Stream data will be discarded by offset mismatch.
- error = this->_recv_and_ack(*packet);
+ error = this->_recv_and_ack(static_cast<QUICPacketR &>(*packet));
break;
default:
QUICConDebug("Unknown packet type: %s(%" PRIu8 ")", QUICDebugNames::packet_type(packet->type()),
@@ -1281,14 +1352,15 @@ QUICNetVConnection::_state_closing_receive_packet()
{
while (this->_packet_recv_queue.size() > 0) {
QUICPacketCreationResult result;
- QUICPacketUPtr packet = this->_dequeue_recv_packet(result);
+ uint8_t packet_buf[QUICPacket::MAX_INSTANCE_SIZE];
+ QUICPacketUPtr packet = this->_dequeue_recv_packet(packet_buf, result);
if (result == QUICPacketCreationResult::SUCCESS) {
switch (packet->type()) {
case QUICPacketType::VERSION_NEGOTIATION:
// Ignore VN packets on closing state
break;
default:
- this->_recv_and_ack(*packet);
+ this->_recv_and_ack(static_cast<QUICPacketR &>(*packet));
break;
}
}
@@ -1312,9 +1384,10 @@ QUICNetVConnection::_state_draining_receive_packet()
{
while (this->_packet_recv_queue.size() > 0) {
QUICPacketCreationResult result;
- QUICPacketUPtr packet = this->_dequeue_recv_packet(result);
+ uint8_t packet_buf[QUICPacket::MAX_INSTANCE_SIZE];
+ QUICPacketUPtr packet = this->_dequeue_recv_packet(packet_buf, result);
if (result == QUICPacketCreationResult::SUCCESS) {
- this->_recv_and_ack(*packet);
+ this->_recv_and_ack(static_cast<QUICPacketR &>(*packet));
// Do NOT schedule WRITE_READY event from this point.
// An endpoint in the draining state MUST NOT send any packets.
}
@@ -1348,25 +1421,34 @@ QUICNetVConnection::_state_common_send_packet()
uint32_t written = 0;
for (int i = static_cast<int>(this->_minimum_encryption_level); i <= static_cast<int>(QUICEncryptionLevel::ONE_RTT); ++i) {
+ uint8_t packet_buf[QUICPacket::MAX_INSTANCE_SIZE];
+
auto level = QUIC_ENCRYPTION_LEVELS[i];
if (level == QUICEncryptionLevel::ONE_RTT && !this->_handshake_handler->is_completed()) {
continue;
}
uint32_t max_packet_size = udp_payload_len - written;
- if (this->netvc_context == NET_VCONNECTION_IN && !this->_verfied_state.is_verified()) {
- max_packet_size = std::min(max_packet_size, this->_verfied_state.windows());
+ if (this->netvc_context == NET_VCONNECTION_IN && !this->_verified_state.is_verified()) {
+ max_packet_size = std::min(max_packet_size, this->_verified_state.windows());
}
QUICPacketInfoUPtr packet_info = std::make_unique<QUICPacketInfo>();
- QUICPacketUPtr packet = this->_packetize_frames(level, max_packet_size, packet_info->frames);
+ QUICPacketUPtr packet = this->_packetize_frames(packet_buf, level, max_packet_size, packet_info->frames);
if (packet) {
- packet_info->packet_number = packet->packet_number();
- packet_info->time_sent = Thread::get_hrtime();
- packet_info->ack_eliciting = packet->is_ack_eliciting();
- packet_info->is_crypto_packet = packet->is_crypto_packet();
- packet_info->in_flight = true;
+ // trigger callback
+ this->_context->trigger(QUICContext::CallbackEvent::PACKET_SEND, packet.get());
+
+ 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;
if (packet_info->ack_eliciting) {
packet_info->sent_bytes = packet->size();
} else {
@@ -1375,9 +1457,9 @@ QUICNetVConnection::_state_common_send_packet()
packet_info->type = packet->type();
packet_info->pn_space = QUICTypeUtil::pn_space(level);
- if (this->netvc_context == NET_VCONNECTION_IN && !this->_verfied_state.is_verified()) {
- QUICConDebug("send to unverified window: %u", this->_verfied_state.windows());
- this->_verfied_state.consume(packet->size());
+ if (this->netvc_context == NET_VCONNECTION_IN && !this->_verified_state.is_verified()) {
+ QUICConDebug("send to unverified window: %u", this->_verified_state.windows());
+ this->_verified_state.consume(packet->size());
}
// TODO: do not write two QUIC Short Header Packets
@@ -1415,6 +1497,9 @@ QUICNetVConnection::_state_common_send_packet()
}
if (packet_count) {
+ this->_context->trigger(QUICContext::CallbackEvent::METRICS_UPDATE, this->_congestion_controller->congestion_window(),
+ this->_congestion_controller->bytes_in_flight(), this->_congestion_controller->current_ssthresh());
+
QUIC_INCREMENT_DYN_STAT_EX(QUICStats::total_packets_sent_stat, packet_count);
net_activity(this, this_ethread());
}
@@ -1447,11 +1532,9 @@ QUICNetVConnection::_store_frame(Ptr<IOBufferBlock> parent_block, size_t &size_a
{
Ptr<IOBufferBlock> new_block = frame.to_io_buffer_block(max_frame_size);
- size_added = 0;
- Ptr<IOBufferBlock> tmp = new_block;
- while (tmp) {
+ size_added = 0;
+ for (Ptr<IOBufferBlock> tmp = new_block; tmp; tmp = tmp->next) {
size_added += tmp->size();
- tmp = tmp->next;
}
if (parent_block == nullptr) {
@@ -1480,7 +1563,8 @@ QUICNetVConnection::_store_frame(Ptr<IOBufferBlock> parent_block, size_t &size_a
}
QUICPacketUPtr
-QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size, std::vector<QUICFrameInfo> &frames)
+QUICNetVConnection::_packetize_frames(uint8_t *packet_buf, QUICEncryptionLevel level, uint64_t max_packet_size,
+ std::vector<QUICFrameInfo> &frames)
{
QUICPacketUPtr packet = QUICPacketFactory::create_null_packet();
if (max_packet_size <= MAX_PACKET_OVERHEAD) {
@@ -1516,24 +1600,17 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa
break;
}
- if (g == this->_stream_manager) {
- // Don't send DATA frames if current path is not validated
- // FIXME will_generate_frame should receive more parameters so we don't need extra checks
- if (auto path = this->_path_manager->get_verified_path(); !path.remote_ep().isValid()) {
- break;
- }
- }
-
// Common block
frame =
g->generate_frame(frame_instance_buffer, level, this->_remote_flow_controller->credit(), max_frame_size, len, seq_num);
if (frame) {
+ this->_context->trigger(QUICContext::CallbackEvent::FRAME_PACKETIZE, *frame);
// Some frame types must not be sent on Initial and Handshake packets
switch (auto t = frame->type(); level) {
case QUICEncryptionLevel::INITIAL:
case QUICEncryptionLevel::HANDSHAKE:
ink_assert(t == QUICFrameType::CRYPTO || t == QUICFrameType::ACK || t == QUICFrameType::PADDING ||
- t == QUICFrameType::CONNECTION_CLOSE);
+ t == QUICFrameType::CONNECTION_CLOSE || t == QUICFrameType::PING);
break;
default:
break;
@@ -1576,7 +1653,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa
// Schedule a packet
if (len != 0) {
// Packet is retransmittable if it's not ack only packet
- packet = this->_build_packet(level, first_block, ack_eliciting, probing, crypto);
+ packet = this->_build_packet(packet_buf, level, first_block, ack_eliciting, probing, crypto);
}
return packet;
@@ -1600,22 +1677,30 @@ QUICNetVConnection::_packetize_closing_frame()
size_t size_added = 0;
uint64_t max_frame_size = static_cast<uint64_t>(max_size);
std::vector<QUICFrameInfo> frames;
- Ptr<IOBufferBlock> parent_block;
- parent_block = nullptr;
- parent_block = this->_store_frame(parent_block, size_added, max_frame_size, *frame, 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));
+ first_block->fill(0);
+ last_block = this->_store_frame(last_block, size_added, max_frame_size, *frame, frames);
QUICEncryptionLevel level = this->_hs_protocol->current_encryption_level();
ink_assert(level != QUICEncryptionLevel::ZERO_RTT);
- this->_the_final_packet = this->_build_packet(level, parent_block, true, false, false);
+ this->_the_final_packet = this->_build_packet(this->_final_packet_buf, level, first_block, true, false, false);
}
QUICConnectionErrorUPtr
-QUICNetVConnection::_recv_and_ack(const QUICPacket &packet, bool *has_non_probing_frame)
+QUICNetVConnection::_recv_and_ack(const QUICPacketR &packet, bool *has_non_probing_frame)
{
ink_assert(packet.type() != QUICPacketType::RETRY);
- const uint8_t *payload = packet.payload();
uint16_t size = packet.payload_length();
+ ats_unique_buf payload_ubuf = ats_unique_malloc(size);
+ uint8_t *payload = payload_ubuf.get();
+ size_t copied_len = 0;
+ for (auto b = packet.payload_block(); b; b = b->next) {
+ memcpy(payload + copied_len, b->start(), b->size());
+ copied_len += b->size();
+ }
QUICPacketNumber packet_num = packet.packet_number();
QUICEncryptionLevel level = QUICTypeUtil::encryption_level(packet.type());
@@ -1627,8 +1712,10 @@ QUICNetVConnection::_recv_and_ack(const QUICPacket &packet, bool *has_non_probin
*has_non_probing_frame = false;
}
- error =
- this->_frame_dispatcher->receive_frames(level, payload, size, ack_only, is_flow_controlled, has_non_probing_frame, &packet);
+ error = this->_frame_dispatcher->receive_frames(*this->_context, level, payload, size, ack_only, is_flow_controlled,
+ has_non_probing_frame, static_cast<const QUICPacketR *>(&packet));
+ this->_context->trigger(QUICContext::CallbackEvent::PACKET_RECV, &packet);
+
if (error != nullptr) {
return error;
}
@@ -1653,21 +1740,15 @@ QUICNetVConnection::_recv_and_ack(const QUICPacket &packet, bool *has_non_probin
}
QUICPacketUPtr
-QUICNetVConnection::_build_packet(QUICEncryptionLevel level, Ptr<IOBufferBlock> parent_block, bool ack_eliciting, bool probing,
- bool crypto)
+QUICNetVConnection::_build_packet(uint8_t *packet_buf, QUICEncryptionLevel level, Ptr<IOBufferBlock> parent_block,
+ bool ack_eliciting, bool probing, bool crypto)
{
QUICPacketType type = QUICTypeUtil::packet_type(level);
QUICPacketUPtr packet = QUICPacketFactory::create_null_packet();
- // FIXME Pass parent_block to create_x_packet
- // No need to make a unique buf here
- ats_unique_buf buf = ats_unique_malloc(2048);
- uint8_t *raw_buf = buf.get();
- size_t len = 0;
- while (parent_block) {
- memcpy(raw_buf + len, parent_block->start(), parent_block->size());
- len += parent_block->size();
- parent_block = parent_block->next;
+ size_t len = 0;
+ for (Ptr<IOBufferBlock> tmp = parent_block; tmp; tmp = tmp->next) {
+ len += tmp->size();
}
switch (type) {
@@ -1688,26 +1769,26 @@ QUICNetVConnection::_build_packet(QUICEncryptionLevel level, Ptr<IOBufferBlock>
}
packet = this->_packet_factory.create_initial_packet(
- dcid, this->_quic_connection_id, this->_largest_acked_packet_number(QUICEncryptionLevel::INITIAL), std::move(buf), len,
- ack_eliciting, probing, crypto, std::move(token), token_len);
+ packet_buf, dcid, this->_quic_connection_id, this->_largest_acked_packet_number(QUICEncryptionLevel::INITIAL), parent_block,
+ len, ack_eliciting, probing, crypto, std::move(token), token_len);
break;
}
case QUICPacketType::HANDSHAKE: {
- packet = this->_packet_factory.create_handshake_packet(this->_peer_quic_connection_id, this->_quic_connection_id,
+ packet = this->_packet_factory.create_handshake_packet(packet_buf, this->_peer_quic_connection_id, this->_quic_connection_id,
this->_largest_acked_packet_number(QUICEncryptionLevel::HANDSHAKE),
- std::move(buf), len, ack_eliciting, probing, crypto);
+ parent_block, len, ack_eliciting, probing, crypto);
break;
}
case QUICPacketType::ZERO_RTT_PROTECTED: {
- packet = this->_packet_factory.create_zero_rtt_packet(this->_original_quic_connection_id, this->_quic_connection_id,
+ packet = this->_packet_factory.create_zero_rtt_packet(packet_buf, this->_original_quic_connection_id, this->_quic_connection_id,
this->_largest_acked_packet_number(QUICEncryptionLevel::ZERO_RTT),
- std::move(buf), len, ack_eliciting, probing);
+ parent_block, len, ack_eliciting, probing);
break;
}
case QUICPacketType::PROTECTED: {
- packet = this->_packet_factory.create_protected_packet(this->_peer_quic_connection_id,
- this->_largest_acked_packet_number(QUICEncryptionLevel::ONE_RTT),
- std::move(buf), len, ack_eliciting, probing);
+ packet = this->_packet_factory.create_short_header_packet(packet_buf, this->_peer_quic_connection_id,
+ this->_largest_acked_packet_number(QUICEncryptionLevel::ONE_RTT),
+ parent_block, len, ack_eliciting, probing);
break;
}
default:
@@ -1750,29 +1831,31 @@ QUICNetVConnection::_handle_error(QUICConnectionErrorUPtr error)
static_cast<unsigned int>(error->cls), QUICDebugNames::error_code(error->code), error->code);
// Connection Error
- this->close(std::move(error));
+ this->close_quic_connection(std::move(error));
}
QUICPacketUPtr
-QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result)
+QUICNetVConnection::_dequeue_recv_packet(uint8_t *packet_buf, QUICPacketCreationResult &result)
{
- QUICPacketUPtr packet = this->_packet_recv_queue.dequeue(result);
+ QUICPacketUPtr packet = this->_packet_recv_queue.dequeue(packet_buf, result);
if (result == QUICPacketCreationResult::SUCCESS) {
if (this->direction() == NET_VCONNECTION_OUT) {
// Reset CID if a server sent back a new CID
- // FIXME This should happen only once
- QUICConnectionId src_cid = packet->source_cid();
- // FIXME src connection id could be zero ? if so, check packet header type.
- if (src_cid != QUICConnectionId::ZERO()) {
- if (this->_peer_quic_connection_id != src_cid) {
- this->_update_peer_cid(src_cid);
+ // FIXME This should happen only once - it should probably be controlled by PathManager
+ if (packet->type() != QUICPacketType::PROTECTED && (packet->type() != QUICPacketType::RETRY || !this->_av_token)) {
+ QUICConnectionId src_cid = static_cast<QUICLongHeaderPacketR &>(*packet).source_cid();
+ // FIXME src connection id could be zero ? if so, check packet header type.
+ if (src_cid != QUICConnectionId::ZERO()) {
+ if (this->_peer_quic_connection_id != src_cid) {
+ this->_update_peer_cid(src_cid);
+ }
}
}
}
- if (!this->_verfied_state.is_verified()) {
- this->_verfied_state.fill(packet->size());
+ if (!this->_verified_state.is_verified()) {
+ this->_verified_state.fill(packet->size());
}
}
@@ -1790,11 +1873,15 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result)
QUICConDebug("Unsupported version");
break;
case QUICPacketCreationResult::SUCCESS:
- if (packet->type() == QUICPacketType::VERSION_NEGOTIATION) {
+ switch (packet->type()) {
+ case QUICPacketType::VERSION_NEGOTIATION:
+ case QUICPacketType::RETRY:
QUICConDebug("[RX] %s packet size=%u", QUICDebugNames::packet_type(packet->type()), packet->size());
- } else {
+ 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());
+ break;
}
break;
default:
@@ -1926,6 +2013,14 @@ QUICNetVConnection::_complete_handshake_if_possible()
this->_handshake_handler->remote_transport_parameters()->getAsUInt(QUICTransportParameterId::ACK_DELAY_EXPONENT);
this->_loss_detector->update_ack_delay_exponent(ack_delay_exponent);
+ const uint8_t *reset_token;
+ uint16_t reset_token_len;
+ reset_token = this->_handshake_handler->remote_transport_parameters()->getAsBytes(QUICTransportParameterId::STATELESS_RESET_TOKEN,
+ reset_token_len);
+ if (reset_token) {
+ this->_rtable->insert({reset_token}, this);
+ }
+
this->_start_application();
return 0;
@@ -1974,12 +2069,16 @@ QUICNetVConnection::_switch_to_established_state()
SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established);
std::shared_ptr<const QUICTransportParameters> remote_tp = this->_handshake_handler->remote_transport_parameters();
+ std::shared_ptr<const QUICTransportParameters> local_tp = this->_handshake_handler->local_transport_parameters();
uint64_t active_cid_limit = remote_tp->getAsUInt(QUICTransportParameterId::ACTIVE_CONNECTION_ID_LIMIT);
if (active_cid_limit) {
this->_alt_con_manager->set_remote_active_cid_limit(active_cid_limit);
}
+ this->set_inactivity_timeout(HRTIME_MSECONDS(std::min(remote_tp->getAsUInt(QUICTransportParameterId::MAX_IDLE_TIMEOUT),
+ local_tp->getAsUInt(QUICTransportParameterId::MAX_IDLE_TIMEOUT))));
+
if (this->direction() == NET_VCONNECTION_OUT) {
uint16_t len;
const uint8_t *pref_addr_buf = remote_tp->getAsBytes(QUICTransportParameterId::PREFERRED_ADDRESS, len);
@@ -2100,12 +2199,7 @@ void
QUICNetVConnection::_update_peer_cid(const QUICConnectionId &new_cid)
{
if (is_debug_tag_set(QUIC_DEBUG_TAG.data())) {
- char old_cid_str[QUICConnectionId::MAX_HEX_STR_LENGTH];
- char new_cid_str[QUICConnectionId::MAX_HEX_STR_LENGTH];
- this->_peer_quic_connection_id.hex(old_cid_str, QUICConnectionId::MAX_HEX_STR_LENGTH);
- new_cid.hex(new_cid_str, QUICConnectionId::MAX_HEX_STR_LENGTH);
-
- QUICConDebug("dcid: %s -> %s", old_cid_str, new_cid_str);
+ QUICConDebug("update peer dcid: %s -> %s", this->_peer_quic_connection_id.hex().c_str(), new_cid.hex().c_str());
}
this->_peer_old_quic_connection_id = this->_peer_quic_connection_id;
@@ -2117,12 +2211,7 @@ void
QUICNetVConnection::_update_local_cid(const QUICConnectionId &new_cid)
{
if (is_debug_tag_set(QUIC_DEBUG_TAG.data())) {
- char old_cid_str[QUICConnectionId::MAX_HEX_STR_LENGTH];
- char new_cid_str[QUICConnectionId::MAX_HEX_STR_LENGTH];
- this->_quic_connection_id.hex(old_cid_str, QUICConnectionId::MAX_HEX_STR_LENGTH);
- new_cid.hex(new_cid_str, QUICConnectionId::MAX_HEX_STR_LENGTH);
-
- QUICConDebug("scid: %s -> %s", old_cid_str, new_cid_str);
+ QUICConDebug("update local dcid: %s -> %s", this->_quic_connection_id.hex().c_str(), new_cid.hex().c_str());
}
this->_quic_connection_id = new_cid;
@@ -2136,12 +2225,7 @@ QUICNetVConnection::_rerandomize_original_cid()
this->_original_quic_connection_id.randomize();
if (is_debug_tag_set(QUIC_DEBUG_TAG.data())) {
- char old_cid_str[QUICConnectionId::MAX_HEX_STR_LENGTH];
- char new_cid_str[QUICConnectionId::MAX_HEX_STR_LENGTH];
- tmp.hex(old_cid_str, QUICConnectionId::MAX_HEX_STR_LENGTH);
- this->_original_quic_connection_id.hex(new_cid_str, QUICConnectionId::MAX_HEX_STR_LENGTH);
-
- QUICConDebug("original cid: %s -> %s", old_cid_str, new_cid_str);
+ QUICConDebug("original cid: %s -> %s", tmp.hex().c_str(), this->_original_quic_connection_id.hex().c_str());
}
}
@@ -2153,12 +2237,13 @@ QUICNetVConnection::_setup_handshake_protocol(shared_SSL_CTX ctx)
QUICTLS *tls = new QUICTLS(this->_pp_key_info, ctx.get(), this->direction(), this->options,
this->_quic_config->client_session_file(), this->_quic_config->client_keylog_file());
SSL_set_ex_data(tls->ssl_handle(), QUIC::ssl_quic_qc_index, static_cast<QUICConnection *>(this));
+ TLSSessionResumptionSupport::bind(tls->ssl_handle(), this);
return tls;
}
QUICConnectionErrorUPtr
-QUICNetVConnection::_state_connection_established_migrate_connection(const QUICPacket &p)
+QUICNetVConnection::_state_connection_established_migrate_connection(const QUICPacketR &p)
{
ink_assert(this->_handshake_handler->is_completed());
@@ -2208,9 +2293,7 @@ QUICNetVConnection::_state_connection_established_migrate_connection(const QUICP
this->_validate_new_path(new_path);
}
} else {
- char dcid_str[QUICConnectionId::MAX_HEX_STR_LENGTH];
- dcid.hex(dcid_str, QUICConnectionId::MAX_HEX_STR_LENGTH);
- QUICConDebug("Connection migration failed cid=%s", dcid_str);
+ QUICConDebug("Connection migration failed cid=%s", dcid.hex().c_str());
}
}
@@ -2265,3 +2348,9 @@ QUICNetVConnection::_handle_periodic_ack_event()
this->_schedule_packet_write_ready();
}
}
+
+const IpEndpoint &
+QUICNetVConnection::_getLocalEndpoint()
+{
+ return local_addr;
+}
diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc
index 9afee71..a6e214d 100644
--- a/iocore/net/QUICPacketHandler.cc
+++ b/iocore/net/QUICPacketHandler.cc
@@ -22,6 +22,9 @@
#include "tscore/ink_config.h"
#include "P_Net.h"
+#include "P_QUICPacketHandler.h"
+#include "P_QUICNetProcessor.h"
+#include "P_QUICNet.h"
#include "P_QUICClosedConCollector.h"
#include "QUICGlobals.h"
@@ -29,6 +32,10 @@
#include "QUICPacket.h"
#include "QUICDebugNames.h"
#include "QUICEvents.h"
+#include "QUICResetTokenTable.h"
+
+#include "QUICMultiCertConfigLoader.h"
+#include "QUICTLS.h"
static constexpr char debug_tag[] = "quic_sec";
@@ -42,7 +49,7 @@ static constexpr char debug_tag[] = "quic_sec";
//
// QUICPacketHandler
//
-QUICPacketHandler::QUICPacketHandler()
+QUICPacketHandler::QUICPacketHandler(QUICResetTokenTable &rtable) : _rtable(rtable)
{
this->_closed_con_collector = new QUICClosedConCollector;
this->_closed_con_collector->mutex = new_ProxyMutex();
@@ -118,11 +125,18 @@ QUICPacketHandler::_send_packet(UDPConnection *udp_con, IpEndpoint &addr, Ptr<IO
get_UDPNetHandler(static_cast<UnixUDPConnection *>(udp_con)->ethread)->signalActivity();
}
+QUICConnection *
+QUICPacketHandler::_check_stateless_reset(const uint8_t *buf, size_t buf_len)
+{
+ return this->_rtable.lookup({buf + (buf_len - 16)});
+}
+
//
// QUICPacketHandlerIn
//
-QUICPacketHandlerIn::QUICPacketHandlerIn(const NetProcessor::AcceptOptions &opt, QUICConnectionTable &ctable)
- : NetAccept(opt), QUICPacketHandler(), _ctable(ctable)
+QUICPacketHandlerIn::QUICPacketHandlerIn(const NetProcessor::AcceptOptions &opt, QUICConnectionTable &ctable,
+ QUICResetTokenTable &rtable)
+ : NetAccept(opt), QUICPacketHandler(rtable), _ctable(ctable)
{
this->mutex = new_ProxyMutex();
// create Connection Table
@@ -141,7 +155,7 @@ NetAccept *
QUICPacketHandlerIn::clone() const
{
NetAccept *na;
- na = new QUICPacketHandlerIn(opt, this->_ctable);
+ na = new QUICPacketHandlerIn(opt, this->_ctable, this->_rtable);
*na = *this;
return na;
}
@@ -254,7 +268,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet)
}
QUICPacketType type = QUICPacketType::UNINITIALIZED;
- QUICPacketLongHeader::type(type, buf, buf_len);
+ QUICLongHeaderPacketR::type(type, buf, buf_len);
if (type == QUICPacketType::INITIAL) {
// [draft-18] 7.2.
// When an Initial packet is sent by a client which has not previously received a Retry packet from the server, it populates
@@ -293,22 +307,33 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet)
// [draft-12] 6.1.2. Server Packet Handling
// Servers MUST drop incoming packets under all other circumstances. They SHOULD send a Stateless Reset (Section 6.10.4) if a
// connection ID is present in the header.
- if ((!vc && !QUICInvariants::is_long_header(buf)) || (vc && vc->in_closed_queue)) {
- if (is_debug_tag_set(debug_tag)) {
- char dcid_str[QUICConnectionId::MAX_HEX_STR_LENGTH];
- dcid.hex(dcid_str, QUICConnectionId::MAX_HEX_STR_LENGTH);
+ if (!vc && !QUICInvariants::is_long_header(buf)) {
+ auto connection = static_cast<QUICNetVConnection *>(this->_check_stateless_reset(buf, buf_len));
+ if (connection) {
+ QUICDebug("Stateless Reset has been received");
+ connection->thread->schedule_imm(connection, QUIC_EVENT_STATELESS_RESET);
+ return;
+ }
- if (!vc && !QUICInvariants::is_long_header(buf)) {
- QUICDebugDS(scid, dcid, "sent Stateless Reset : connection not found, dcid=%s", dcid_str);
- } else if (vc && vc->in_closed_queue) {
- QUICDebugDS(scid, dcid, "sent Stateless Reset : connection is already closed, dcid=%s", dcid_str);
- }
+ bool sent =
+ this->_send_stateless_reset(dcid, params->instance_id(), udp_packet->getConnection(), udp_packet->from, buf_len - 1);
+ 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());
}
- QUICStatelessResetToken token(dcid, params->instance_id());
- auto packet = QUICPacketFactory::create_stateless_reset_packet(dcid, token);
- this->_send_packet(*packet, udp_packet->getConnection(), udp_packet->from, 1200, nullptr, 0);
+ return;
+
+ } else if (vc && vc->in_closed_queue) {
+ bool sent =
+ this->_send_stateless_reset(dcid, params->instance_id(), udp_packet->getConnection(), udp_packet->from, buf_len - 1);
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());
+ }
+
return;
}
@@ -323,13 +348,11 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet)
QUICConnectionId peer_cid = scid;
if (is_debug_tag_set("quic_sec")) {
- char client_dcid_hex_str[QUICConnectionId::MAX_HEX_STR_LENGTH];
- original_cid.hex(client_dcid_hex_str, QUICConnectionId::MAX_HEX_STR_LENGTH);
- QUICDebugDS(peer_cid, original_cid, "client initial dcid=%s", client_dcid_hex_str);
+ QUICDebugDS(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->_ctable);
+ vc->init(peer_cid, original_cid, cid_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();
@@ -373,7 +396,7 @@ QUICPacketHandlerIn::_stateless_retry(const uint8_t *buf, uint64_t buf_len, UDPC
QUICConnectionId dcid, QUICConnectionId scid, QUICConnectionId *original_cid)
{
QUICPacketType type = QUICPacketType::UNINITIALIZED;
- QUICPacketLongHeader::type(type, buf, buf_len);
+ QUICPacketR::type(type, buf, buf_len);
if (type != QUICPacketType::INITIAL) {
return 1;
@@ -383,7 +406,7 @@ QUICPacketHandlerIn::_stateless_retry(const uint8_t *buf, uint64_t buf_len, UDPC
size_t token_length = 0;
uint8_t token_length_field_len = 0;
size_t token_length_field_offset = 0;
- if (!QUICPacketLongHeader::token_length(token_length, token_length_field_len, token_length_field_offset, buf, buf_len)) {
+ if (!QUICInitialPacketR::token_length(token_length, token_length_field_len, token_length_field_offset, buf, buf_len)) {
return -1;
}
@@ -391,10 +414,11 @@ QUICPacketHandlerIn::_stateless_retry(const uint8_t *buf, uint64_t buf_len, UDPC
QUICRetryToken token(from, dcid);
QUICConnectionId local_cid;
local_cid.randomize();
- QUICPacketUPtr retry_packet = QUICPacketFactory::create_retry_packet(scid, local_cid, dcid, token);
+ QUICPacketUPtr retry_packet = QUICPacketFactory::create_retry_packet(scid, local_cid, token);
- QUICDebug("[TX] %s packet ODCID=%" PRIx64, QUICDebugNames::packet_type(retry_packet->type()),
- static_cast<uint64_t>(static_cast<const QUICPacketLongHeader &>(retry_packet->header()).original_dcid()));
+ 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]);
this->_send_packet(*retry_packet, connection, from, 1200, nullptr, 0);
return -2;
@@ -405,8 +429,13 @@ 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));
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]);
+ this->_send_invalid_token_error(buf, buf_len, connection, from);
return -3;
}
} else {
@@ -418,10 +447,61 @@ QUICPacketHandlerIn::_stateless_retry(const uint8_t *buf, uint64_t buf_len, UDPC
return 0;
}
+bool
+QUICPacketHandlerIn::_send_stateless_reset(QUICConnectionId dcid, uint32_t instance_id, UDPConnection *udp_con, IpEndpoint &addr,
+ size_t maximum_size)
+{
+ QUICStatelessResetToken token(dcid, instance_id);
+ auto packet = QUICPacketFactory::create_stateless_reset_packet(token, maximum_size);
+ if (packet) {
+ this->_send_packet(*packet, udp_con, addr, 1200, nullptr, 0);
+ return true;
+ }
+ return false;
+}
+
+void
+QUICPacketHandlerIn::_send_invalid_token_error(const uint8_t *initial_packet, uint64_t initial_packet_len,
+ UDPConnection *connection, IpEndpoint from)
+{
+ QUICConnectionId scid_in_initial;
+ QUICConnectionId dcid_in_initial;
+ QUICInvariants::scid(scid_in_initial, initial_packet, initial_packet_len);
+ QUICInvariants::dcid(dcid_in_initial, initial_packet, initial_packet_len);
+
+ // Create CONNECTION_CLOSE frame
+ auto error = std::make_unique<QUICConnectionError>(QUICTransErrorCode::INVALID_TOKEN);
+ uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE];
+ QUICFrame *frame = QUICFrameFactory::create_connection_close_frame(frame_buf, *error);
+ Ptr<IOBufferBlock> block = frame->to_io_buffer_block(1200);
+ size_t block_len = 0;
+ for (Ptr<IOBufferBlock> tmp = block; tmp; tmp = tmp->next) {
+ block_len += tmp->size();
+ }
+ frame->~QUICFrame();
+
+ // Prepare for packet protection
+ QUICPacketProtectionKeyInfo ppki;
+ ppki.set_context(QUICPacketProtectionKeyInfo::Context::SERVER);
+ QUICPacketFactory pf(ppki);
+ 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);
+
+ // Create INITIAL packet
+ QUICConnectionId scid;
+ scid.randomize();
+ uint8_t packet_buf[QUICPacket::MAX_INSTANCE_SIZE];
+ QUICPacketUPtr cc_packet = pf.create_initial_packet(packet_buf, scid_in_initial, scid, 0, block, block_len, 0, 0, 1);
+
+ this->_send_packet(*cc_packet, connection, from, 0, &php, scid_in_initial);
+}
+
//
// QUICPacketHandlerOut
//
-QUICPacketHandlerOut::QUICPacketHandlerOut() : Continuation(new_ProxyMutex()), QUICPacketHandler()
+QUICPacketHandlerOut::QUICPacketHandlerOut(QUICResetTokenTable &rtable) : Continuation(new_ProxyMutex()), QUICPacketHandler(rtable)
{
SET_HANDLER(&QUICPacketHandlerOut::event_handler);
}
@@ -466,10 +546,11 @@ QUICPacketHandlerOut::_get_continuation()
void
QUICPacketHandlerOut::_recv_packet(int event, UDPPacket *udp_packet)
{
- if (is_debug_tag_set(debug_tag)) {
- IOBufferBlock *block = udp_packet->getIOBlockChain();
- const uint8_t *buf = reinterpret_cast<uint8_t *>(block->buf());
+ IOBufferBlock *block = udp_packet->getIOBlockChain();
+ const uint8_t *buf = reinterpret_cast<uint8_t *>(block->buf());
+ uint64_t buf_len = block->size();
+ 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"),
@@ -477,6 +558,24 @@ QUICPacketHandlerOut::_recv_packet(int event, UDPPacket *udp_packet)
ats_ip_nptop(&udp_packet->to.sa, ipb_to, sizeof(ipb_to)), udp_packet->getPktLength());
}
+ QUICConnectionId dcid;
+ if (!QUICInvariants::dcid(dcid, buf, buf_len)) {
+ QUICDebug("Ignore packet - payload is too small");
+ udp_packet->free();
+ return;
+ }
+
+ if (!QUICInvariants::is_long_header(buf) && dcid != this->_vc->connection_id()) {
+ auto connection = static_cast<QUICNetVConnection *>(this->_check_stateless_reset(buf, buf_len));
+ if (connection) {
+ if (connection->connection_id() == this->_vc->connection_id()) {
+ QUICDebug("Stateless Reset has been received");
+ this->_vc->thread->schedule_imm(this->_vc, QUIC_EVENT_STATELESS_RESET);
+ }
+ return;
+ }
+ }
+
this->_vc->handle_received_packet(udp_packet);
eventProcessor.schedule_imm(this->_vc, ET_CALL, QUIC_EVENT_PACKET_READ_READY, nullptr);
}
diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am
index 8acdb53..75c4daf 100644
--- a/iocore/net/quic/Makefile.am
+++ b/iocore/net/quic/Makefile.am
@@ -30,7 +30,7 @@ AM_CPPFLAGS += \
-I$(abs_top_srcdir)/mgmt \
-I$(abs_top_srcdir)/mgmt/utils \
$(TS_INCLUDES) \
- @OPENSSL_INCLUDES@
+ @OPENSSL_INCLUDES@ @YAMLCPP_INCLUDES@
noinst_LIBRARIES = libquic.a
@@ -40,11 +40,20 @@ QUICPPProtector_impl = QUICPacketPayloadProtector_boringssl.cc
QUICTLS_impl = QUICTLS_boringssl.cc
QUICKeyGenerator_impl = QUICKeyGenerator_boringssl.cc
else
+if ENABLE_QUIC_OLD_API
+QUICPHProtector_impl = QUICPacketHeaderProtector_legacy.cc
+QUICPPProtector_impl = QUICPacketPayloadProtector_legacy.cc
+QUICTLS_impl = QUICTLS_legacy.cc
+QUICKeyGenerator_impl = QUICKeyGenerator_legacy.cc
+else
QUICPHProtector_impl = QUICPacketHeaderProtector_openssl.cc
QUICPPProtector_impl = QUICPacketPayloadProtector_openssl.cc
QUICTLS_impl = QUICTLS_openssl.cc
QUICKeyGenerator_impl = QUICKeyGenerator_openssl.cc
endif
+endif
+
+QLog_impl = qlog/QLogEvent.cc qlog/QLogFrame.cc qlog/QLog.cc
libquic_a_SOURCES = \
QUICGlobals.cc \
@@ -86,6 +95,8 @@ libquic_a_SOURCES = \
QUICPathManager.cc \
QUICPathValidator.cc \
QUICPinger.cc \
+ QUICRetryIntegrityTag.cc \
+ QUICResetTokenTable.cc \
QUICFrameGenerator.cc \
QUICFrameRetransmitter.cc \
QUICAddrVerifyState.cc \
@@ -95,7 +106,8 @@ libquic_a_SOURCES = \
QUICStreamFactory.cc \
QUICPadder.cc \
QUICContext.cc \
- QUICTokenCreator.cc
+ QUICTokenCreator.cc \
+ $(QLog_impl)
#
# Check Programs
diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h
index 0c78e30..68e421a 100644
--- a/iocore/net/quic/Mock.h
+++ b/iocore/net/quic/Mock.h
@@ -29,11 +29,15 @@
#include "QUICStreamManager.h"
#include "QUICLossDetector.h"
#include "QUICEvents.h"
+#include "QUICPacketProtectionKeyInfo.h"
+#include "QUICPinger.h"
+#include "QUICPadder.h"
+#include "QUICHandshakeProtocol.h"
class MockQUICContext;
using namespace std::literals;
-std::string_view negotiated_application_name_sv = "h3-23"sv;
+std::string_view negotiated_application_name_sv = "h3-27"sv;
class MockQUICLDConfig : public QUICLDConfig
{
@@ -95,6 +99,35 @@ class MockQUICCCConfig : public QUICCCConfig
}
};
+class MockQUICPathManager : public QUICPathManager
+{
+public:
+ virtual ~MockQUICPathManager() {}
+ virtual const QUICPath &
+ get_current_path()
+ {
+ return _path;
+ }
+ virtual const QUICPath &
+ get_verified_path()
+ {
+ return _path;
+ }
+ virtual void
+ open_new_path(const QUICPath &path, ink_hrtime timeout_in)
+ {
+ return;
+ }
+ virtual void
+ set_trusted_path(const QUICPath &path)
+ {
+ return;
+ }
+
+private:
+ QUICPath _path = {{}, {}};
+};
+
class MockQUICConnectionInfoProvider : public QUICConnectionInfoProvider
{
QUICConnectionId
@@ -169,7 +202,7 @@ class MockQUICConnectionInfoProvider : public QUICConnectionInfoProvider
class MockQUICStreamManager : public QUICStreamManager
{
public:
- MockQUICStreamManager(QUICConnectionInfoProvider *info) : QUICStreamManager(info, nullptr, nullptr) {}
+ MockQUICStreamManager(QUICContext *context) : QUICStreamManager(context, nullptr) {}
// Override
virtual QUICConnectionErrorUPtr
@@ -349,7 +382,12 @@ public:
}
void
- close(QUICConnectionErrorUPtr error) override
+ close_quic_connection(QUICConnectionErrorUPtr error) override
+ {
+ }
+
+ void
+ reset_quic_connection() override
{
}
@@ -362,7 +400,7 @@ public:
QUICStreamManager *
stream_manager() override
{
- return &_stream_manager;
+ return nullptr;
}
bool
@@ -397,9 +435,8 @@ public:
int _transmit_count = 0;
int _retransmit_count = 0;
Ptr<ProxyMutex> _mutex;
- int _totalFrameCount = 0;
- int _frameCount[256] = {0};
- MockQUICStreamManager _stream_manager = {this};
+ int _totalFrameCount = 0;
+ int _frameCount[256] = {0};
QUICTransportParametersInEncryptedExtensions dummy_transport_parameters();
NetVConnectionContext_t _direction;
@@ -443,6 +480,21 @@ public:
{
return 0;
}
+ virtual uint32_t
+ bytes_in_flight() const override
+ {
+ return 0;
+ }
+ virtual uint32_t
+ congestion_window() const override
+ {
+ return 0;
+ }
+ virtual uint32_t
+ current_ssthresh() const override
+ {
+ return 0;
+ }
// for Test
int
@@ -498,15 +550,16 @@ public:
}
};
-class MockQUICContext : public QUICContext, public QUICLDContext, public QUICCCContext
+class MockQUICContext : public QUICContext
{
public:
- MockQUICContext()
+ MockQUICContext() : QUICContext()
{
- _info = std::make_unique<MockQUICConnectionInfoProvider>();
- _key_info = std::make_unique<MockQUICPacketProtectionKeyInfo>();
- _ld_config = std::make_unique<MockQUICLDConfig>();
- _cc_config = std::make_unique<MockQUICCCConfig>();
+ _info = std::make_unique<MockQUICConnectionInfoProvider>();
+ _key_info = std::make_unique<MockQUICPacketProtectionKeyInfo>();
+ _path_manager = std::make_unique<MockQUICPathManager>();
+ _ld_config = std::make_unique<MockQUICLDConfig>();
+ _cc_config = std::make_unique<MockQUICCCConfig>();
}
virtual QUICConnectionInfoProvider *
@@ -543,6 +596,12 @@ public:
return *_cc_config;
}
+ virtual QUICPathManager *
+ path_manager() const override
+ {
+ return _path_manager.get();
+ }
+
private:
QUICConfig::scoped_config _config;
QUICRTTMeasure _rtt_measure;
@@ -550,6 +609,7 @@ private:
std::unique_ptr<QUICPacketProtectionKeyInfo> _key_info;
std::unique_ptr<QUICLDConfig> _ld_config;
std::unique_ptr<QUICCCConfig> _cc_config;
+ std::unique_ptr<MockQUICPathManager> _path_manager;
};
class MockQUICLossDetector : public QUICLossDetector
@@ -599,9 +659,29 @@ public:
}
};
-class MockQUICPacket : public QUICPacket
+class MockQUICPacketR : public QUICPacketR
{
public:
+ MockQUICPacketR() : QUICPacketR(nullptr, {}, {}) {}
+
+ QUICPacketType
+ type() const override
+ {
+ return QUICPacketType::PROTECTED;
+ }
+
+ QUICConnectionId
+ destination_cid() const override
+ {
+ return QUICConnectionId::ZERO();
+ }
+
+ QUICPacketNumber
+ packet_number() const override
+ {
+ return 0;
+ }
+
const IpEndpoint &
from() const override
{
@@ -637,7 +717,7 @@ public:
MockQUICHandshakeProtocol(QUICPacketProtectionKeyInfo &pp_key_info) : QUICHandshakeProtocol(pp_key_info) {}
int
- handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) override
+ handshake(QUICHandshakeMsgs **out, const QUICHandshakeMsgs *in) override
{
return true;
}
diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc
index 98ca898..43167da 100644
--- a/iocore/net/quic/QUICAckFrameCreator.cc
+++ b/iocore/net/quic/QUICAckFrameCreator.cc
@@ -187,11 +187,8 @@ QUICAckFrameManager::QUICAckFrameCreator::push_back(QUICPacketNumber packet_numb
this->_should_send = true;
}
- // every 2 full-packet should send a ack frame like tcp
- this->_size_unsend += size;
- // FIXME: this size should be fixed with PMTU
- if (this->_size_unsend > 2 * 1480) {
- this->_size_unsend = 0;
+ // every 2 ack-eliciting packet should send a ack frame
+ if (!ack_only && ++this->_ack_eliciting_count % 2 == 0) {
this->_should_send = true;
}
@@ -224,7 +221,7 @@ QUICAckFrameManager::QUICAckFrameCreator::clear()
this->_largest_ack_number = 0;
this->_largest_ack_received_time = 0;
this->_latest_packet_received_time = 0;
- this->_size_unsend = 0;
+ this->_ack_eliciting_count = 0;
this->_should_send = false;
this->_available = false;
}
diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h
index 58e28e8..42a7540 100644
--- a/iocore/net/quic/QUICAckFrameCreator.h
+++ b/iocore/net/quic/QUICAckFrameCreator.h
@@ -69,7 +69,7 @@ public:
bool _available = false; // packet_number has data to sent
bool _should_send = false; // ack frame should be sent immediately
bool _has_new_data = false; // new data after last sent
- size_t _size_unsend = 0;
+ uint32_t _ack_eliciting_count = 0; // every two ack-eliciting packet should send ack immediatly
uint16_t _max_ack_delay = 25;
QUICPacketNumber _largest_ack_number = 0;
QUICPacketNumber _expect_next = 0;
diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc
index 4e39e93..569581c 100644
--- a/iocore/net/quic/QUICAltConnectionManager.cc
+++ b/iocore/net/quic/QUICAltConnectionManager.cc
@@ -26,25 +26,28 @@
#include "tscore/ink_defs.h"
#include "QUICAltConnectionManager.h"
#include "QUICConnectionTable.h"
+#include "QUICResetTokenTable.h"
static constexpr char V_DEBUG_TAG[] = "v_quic_alt_con";
#define QUICACMVDebug(fmt, ...) Debug(V_DEBUG_TAG, "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__)
-QUICAltConnectionManager::QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable,
+QUICAltConnectionManager::QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable, QUICResetTokenTable &rtable,
const QUICConnectionId &peer_initial_cid, uint32_t instance_id,
uint8_t local_active_cid_limit, const IpEndpoint *preferred_endpoint_ipv4,
const IpEndpoint *preferred_endpoint_ipv6)
- : _qc(qc), _ctable(ctable), _instance_id(instance_id), _local_active_cid_limit(local_active_cid_limit)
+ : _qc(qc), _ctable(ctable), _rtable(rtable), _instance_id(instance_id), _local_active_cid_limit(local_active_cid_limit)
{
// Sequence number of the initial CID is 0
this->_alt_quic_connection_ids_remote.push_back({0, peer_initial_cid, {}, {true}});
+ this->_alt_quic_connection_ids_local[0].seq_num = 0;
+ this->_alt_quic_connection_ids_local[0].advertised = true;
if ((preferred_endpoint_ipv4 && !ats_ip_addr_port_eq(*preferred_endpoint_ipv4, qc->five_tuple().source())) ||
(preferred_endpoint_ipv6 && !ats_ip_addr_port_eq(*preferred_endpoint_ipv6, qc->five_tuple().source()))) {
- this->_alt_quic_connection_ids_local[0] = this->_generate_next_alt_con_info();
+ this->_alt_quic_connection_ids_local[1] = this->_generate_next_alt_con_info();
// This alt cid will be advertised via Transport Parameter, so no need to advertise it via NCID frame
- this->_alt_quic_connection_ids_local[0].advertised = true;
+ this->_alt_quic_connection_ids_local[1].advertised = true;
IpEndpoint empty_endpoint_ipv4;
IpEndpoint empty_endpoint_ipv6;
@@ -59,8 +62,8 @@ QUICAltConnectionManager::QUICAltConnectionManager(QUICConnection *qc, QUICConne
// FIXME Check nullptr dereference
this->_local_preferred_address =
- new QUICPreferredAddress(*preferred_endpoint_ipv4, *preferred_endpoint_ipv6, this->_alt_quic_connection_ids_local[0].id,
- this->_alt_quic_connection_ids_local[0].token);
+ new QUICPreferredAddress(*preferred_endpoint_ipv4, *preferred_endpoint_ipv6, this->_alt_quic_connection_ids_local[1].id,
+ this->_alt_quic_connection_ids_local[1].token);
}
}
@@ -116,9 +119,7 @@ QUICAltConnectionManager::_generate_next_alt_con_info()
}
if (is_debug_tag_set(V_DEBUG_TAG)) {
- char new_cid_str[QUICConnectionId::MAX_HEX_STR_LENGTH];
- conn_id.hex(new_cid_str, QUICConnectionId::MAX_HEX_STR_LENGTH);
- QUICACMVDebug("alt-cid=%s", new_cid_str);
+ QUICACMVDebug("alt-cid=%s", conn_id.hex().c_str());
}
return aci;
@@ -127,7 +128,7 @@ QUICAltConnectionManager::_generate_next_alt_con_info()
void
QUICAltConnectionManager::_init_alt_connection_ids()
{
- for (int i = 0; i < this->_remote_active_cid_limit; ++i) {
+ for (int i = this->_alt_quic_connection_id_seq_num + 1; i < this->_remote_active_cid_limit; ++i) {
this->_alt_quic_connection_ids_local[i] = this->_generate_next_alt_con_info();
}
this->_need_advertise = true;
@@ -136,16 +137,6 @@ QUICAltConnectionManager::_init_alt_connection_ids()
bool
QUICAltConnectionManager::_update_alt_connection_id(uint64_t chosen_seq_num)
{
- // Seq 0 is special so it's not in the array
- if (chosen_seq_num == 0) {
- return true;
- }
-
- // Seq 1 is for Preferred Address
- if (chosen_seq_num == 1) {
- return true;
- }
-
for (int i = 0; i < this->_remote_active_cid_limit; ++i) {
if (this->_alt_quic_connection_ids_local[i].seq_num == chosen_seq_num) {
this->_alt_quic_connection_ids_local[i] = this->_generate_next_alt_con_info();
@@ -166,10 +157,17 @@ QUICAltConnectionManager::_register_remote_connection_id(const QUICNewConnection
error = std::make_unique<QUICConnectionError>(QUICTransErrorCode::PROTOCOL_VIOLATION, "received zero-length cid",
QUICFrameType::NEW_CONNECTION_ID);
} else {
- int unused = std::count_if(this->_alt_quic_connection_ids_remote.begin(), this->_alt_quic_connection_ids_remote.end(),
- [](AltConnectionInfo info) { return info.used == false && info.seq_num != 1; });
+ int unused = 0;
+ for (auto &&x : this->_alt_quic_connection_ids_remote) {
+ if (x.seq_num == frame.sequence()) {
+ return error;
+ }
+ if (x.used == false && x.seq_num != 1) {
+ ++unused;
+ }
+ }
if (unused > this->_local_active_cid_limit) {
- error = std::make_unique<QUICConnectionError>(QUICTransErrorCode::PROTOCOL_VIOLATION, "received too many alt CIDs",
+ error = std::make_unique<QUICConnectionError>(QUICTransErrorCode::CONNECTION_ID_LIMIT_ERROR, "received too many alt CIDs",
QUICFrameType::NEW_CONNECTION_ID);
} else {
this->_alt_quic_connection_ids_remote.push_back(
@@ -215,6 +213,7 @@ QUICAltConnectionManager::migrate_to_alt_cid()
continue;
}
info.used = true;
+ this->_rtable.insert(info.token, this->_qc);
return info.id;
}
@@ -250,6 +249,7 @@ QUICAltConnectionManager::drop_cid(const QUICConnectionId &cid)
if (it->id == cid) {
QUICACMVDebug("Dropping advertized CID %" PRIx32 " seq# %" PRIu64, it->id.h32(), it->seq_num);
this->_retired_seq_nums.push(it->seq_num);
+ this->_rtable.erase(it->token);
this->_alt_quic_connection_ids_remote.erase(it);
return;
}
diff --git a/iocore/net/quic/QUICAltConnectionManager.h b/iocore/net/quic/QUICAltConnectionManager.h
index 09b99ca..f92e90e 100644
--- a/iocore/net/quic/QUICAltConnectionManager.h
+++ b/iocore/net/quic/QUICAltConnectionManager.h
@@ -31,12 +31,14 @@
#include "QUICConnection.h"
class QUICConnectionTable;
+class QUICResetTokenTable;
class QUICAltConnectionManager : public QUICFrameHandler, public QUICFrameGenerator
{
public:
- QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable, const QUICConnectionId &peer_initial_cid,
- uint32_t instance_id, uint8_t active_cid_limit, const IpEndpoint *preferred_endpoint_ipv4 = nullptr,
+ QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable, QUICResetTokenTable &rtable,
+ const QUICConnectionId &peer_initial_cid, uint32_t instance_id, uint8_t active_cid_limit,
+ const IpEndpoint *preferred_endpoint_ipv4 = nullptr,
const IpEndpoint *preferred_endpoint_ipv6 = nullptr);
~QUICAltConnectionManager();
@@ -95,6 +97,7 @@ private:
QUICConnection *_qc = nullptr;
QUICConnectionTable &_ctable;
+ QUICResetTokenTable &_rtable;
AltConnectionInfo _alt_quic_connection_ids_local[8]; // 8 is perhaps enough
std::vector<AltConnectionInfo> _alt_quic_connection_ids_remote;
std::queue<uint64_t> _retired_seq_nums;
diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc
index 1cfe703..cc44d00 100644
--- a/iocore/net/quic/QUICConfig.cc
+++ b/iocore/net/quic/QUICConfig.cc
@@ -49,10 +49,6 @@ quic_new_ssl_ctx()
SSL_CTX_set_max_early_data(ssl_ctx, UINT32_C(0xFFFFFFFF));
- SSL_CTX_add_custom_ext(ssl_ctx, QUICTransportParametersHandler::TRANSPORT_PARAMETER_ID,
- SSL_EXT_TLS_ONLY | SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS,
- &QUICTransportParametersHandler::add, &QUICTransportParametersHandler::free, nullptr,
- &QUICTransportParametersHandler::parse, nullptr);
#else
// QUIC Transport Parameters are accesible with SSL_set_quic_transport_params and SSL_get_peer_quic_transport_params
#endif
@@ -61,6 +57,11 @@ quic_new_ssl_ctx()
// tatsuhiro-t's custom OpenSSL for QUIC draft-13
// https://github.com/tatsuhiro-t/openssl/tree/quic-draft-13
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_QUIC_HACK);
+ SSL_CTX_add_custom_ext(ssl_ctx, QUICTransportParametersHandler::TRANSPORT_PARAMETER_ID,
+ SSL_EXT_TLS_ONLY | SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS,
+ &QUICTransportParametersHandler::add, &QUICTransportParametersHandler::free, nullptr,
+ &QUICTransportParametersHandler::parse, nullptr);
+
#endif
return ssl_ctx;
@@ -120,11 +121,16 @@ QUICConfigParams::initialize()
REC_EstablishStaticConfigInt32U(this->_stateless_retry, "proxy.config.quic.server.stateless_retry_enabled");
REC_EstablishStaticConfigInt32U(this->_vn_exercise_enabled, "proxy.config.quic.client.vn_exercise_enabled");
REC_EstablishStaticConfigInt32U(this->_cm_exercise_enabled, "proxy.config.quic.client.cm_exercise_enabled");
+ REC_EstablishStaticConfigInt32U(this->_quantum_readiness_test_enabled_out,
+ "proxy.config.quic.client.quantum_readiness_test_enabled");
+ REC_EstablishStaticConfigInt32U(this->_quantum_readiness_test_enabled_in,
+ "proxy.config.quic.server.quantum_readiness_test_enabled");
REC_ReadConfigStringAlloc(this->_server_supported_groups, "proxy.config.quic.server.supported_groups");
REC_ReadConfigStringAlloc(this->_client_supported_groups, "proxy.config.quic.client.supported_groups");
REC_ReadConfigStringAlloc(this->_client_session_file, "proxy.config.quic.client.session_file");
REC_ReadConfigStringAlloc(this->_client_keylog_file, "proxy.config.quic.client.keylog_file");
+ REC_ReadConfigStringAlloc(this->_qlog_dir, "proxy.config.quic.qlog_dir");
// Transport Parameters
REC_EstablishStaticConfigInt32U(this->_no_activity_timeout_in, "proxy.config.quic.no_activity_timeout_in");
@@ -159,6 +165,7 @@ QUICConfigParams::initialize()
REC_EstablishStaticConfigInt32U(this->_max_ack_delay_out, "proxy.config.quic.max_ack_delay_out");
REC_EstablishStaticConfigInt32U(this->_active_cid_limit_in, "proxy.config.quic.active_cid_limit_in");
REC_EstablishStaticConfigInt32U(this->_active_cid_limit_out, "proxy.config.quic.active_cid_limit_out");
+ REC_EstablishStaticConfigInt32U(this->_disable_active_migration, "proxy.config.quic.disable_active_migration");
// Loss Detection
REC_EstablishStaticConfigInt32U(this->_ld_packet_threshold, "proxy.config.quic.loss_detection.packet_threshold");
@@ -245,6 +252,18 @@ QUICConfigParams::cm_exercise_enabled() const
}
uint32_t
+QUICConfigParams::quantum_readiness_test_enabled_in() const
+{
+ return this->_quantum_readiness_test_enabled_in;
+}
+
+uint32_t
+QUICConfigParams::quantum_readiness_test_enabled_out() const
+{
+ return this->_quantum_readiness_test_enabled_out;
+}
+
+uint32_t
QUICConfigParams::initial_max_data_in() const
{
return this->_initial_max_data_in;
@@ -352,6 +371,12 @@ QUICConfigParams::active_cid_limit_out() const
return this->_active_cid_limit_out;
}
+bool
+QUICConfigParams::disable_active_migration() const
+{
+ return this->_disable_active_migration;
+}
+
const char *
QUICConfigParams::server_supported_groups() const
{
@@ -447,6 +472,12 @@ QUICConfigParams::client_keylog_file() const
return this->_client_keylog_file;
}
+const char *
+QUICConfigParams::qlog_dir() const
+{
+ return this->_qlog_dir;
+}
+
//
// QUICConfig
//
diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h
index 67106e6..38a655a 100644
--- a/iocore/net/quic/QUICConfig.h
+++ b/iocore/net/quic/QUICConfig.h
@@ -40,11 +40,14 @@ public:
uint32_t stateless_retry() const;
uint32_t vn_exercise_enabled() const;
uint32_t cm_exercise_enabled() const;
+ uint32_t quantum_readiness_test_enabled_in() const;
+ uint32_t quantum_readiness_test_enabled_out() const;
const char *server_supported_groups() const;
const char *client_supported_groups() const;
const char *client_session_file() const;
const char *client_keylog_file() const;
+ const char *qlog_dir() const;
shared_SSL_CTX client_ssl_ctx() const;
@@ -71,6 +74,7 @@ public:
uint8_t max_ack_delay_out() const;
uint8_t active_cid_limit_in() const;
uint8_t active_cid_limit_out() const;
+ bool disable_active_migration() const;
// Loss Detection
uint32_t ld_packet_threshold() const;
@@ -93,15 +97,18 @@ private:
// TODO: make configurable
static const uint8_t _scid_len = 18; //< Length of Source Connection ID
- uint32_t _instance_id = 0;
- uint32_t _stateless_retry = 0;
- uint32_t _vn_exercise_enabled = 0;
- uint32_t _cm_exercise_enabled = 0;
+ uint32_t _instance_id = 0;
+ uint32_t _stateless_retry = 0;
+ uint32_t _vn_exercise_enabled = 0;
+ uint32_t _cm_exercise_enabled = 0;
+ uint32_t _quantum_readiness_test_enabled_in = 0;
+ uint32_t _quantum_readiness_test_enabled_out = 0;
char *_server_supported_groups = nullptr;
char *_client_supported_groups = nullptr;
char *_client_session_file = nullptr;
char *_client_keylog_file = nullptr;
+ char *_qlog_dir = nullptr;
shared_SSL_CTX _client_ssl_ctx = nullptr;
@@ -130,6 +137,7 @@ private:
uint32_t _max_ack_delay_out = 0;
uint32_t _active_cid_limit_in = 0;
uint32_t _active_cid_limit_out = 0;
+ uint32_t _disable_active_migration = 0;
// [draft-17 recovery] 6.4.1. Constants of interest
uint32_t _ld_packet_threshold = 3;
diff --git a/iocore/net/quic/QUICCongestionController.h b/iocore/net/quic/QUICCongestionController.h
index 46341dc..5afa8f0 100644
--- a/iocore/net/quic/QUICCongestionController.h
+++ b/iocore/net/quic/QUICCongestionController.h
@@ -23,6 +23,8 @@
#pragma once
+#include "QUICFrame.h"
+
struct QUICPacketInfo {
// 6.3.1. Sent Packet Fields
QUICPacketNumber packet_number;
@@ -42,6 +44,13 @@ struct QUICPacketInfo {
class QUICCongestionController
{
public:
+ enum class State : uint8_t {
+ RECOVERY,
+ CONGESTION_AVOIDANCE,
+ SLOW_START,
+ APPPLICATION_LIMITED,
+ };
+
virtual ~QUICCongestionController() {}
virtual void on_packet_sent(size_t bytes_sent) = 0;
virtual void on_packet_acked(const QUICPacketInfo &acked_packet) = 0;
@@ -50,4 +59,8 @@ public:
virtual void add_extra_credit() = 0;
virtual void reset() = 0;
virtual uint32_t credit() 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 28c5a83..ed75dc6 100644
--- a/iocore/net/quic/QUICConnection.h
+++ b/iocore/net/quic/QUICConnection.h
@@ -53,8 +53,9 @@ public:
class QUICConnection : public QUICFrameHandler, public QUICConnectionInfoProvider
{
public:
- virtual QUICStreamManager *stream_manager() = 0;
- virtual void close(QUICConnectionErrorUPtr error) = 0;
- virtual void handle_received_packet(UDPPacket *packeet) = 0;
- virtual void ping() = 0;
+ virtual QUICStreamManager *stream_manager() = 0;
+ virtual void close_quic_connection(QUICConnectionErrorUPtr error) = 0;
+ virtual void reset_quic_connection() = 0;
+ virtual void handle_received_packet(UDPPacket *packeet) = 0;
+ virtual void ping() = 0;
};
diff --git a/iocore/net/quic/QUICContext.cc b/iocore/net/quic/QUICContext.cc
index 7ccb9e4..4d0d501 100644
--- a/iocore/net/quic/QUICContext.cc
+++ b/iocore/net/quic/QUICContext.cc
@@ -100,48 +100,55 @@ private:
const QUICConfigParams *_params;
};
-QUICContextImpl::QUICContextImpl(QUICRTTProvider *rtt, QUICConnectionInfoProvider *info,
- QUICPacketProtectionKeyInfoProvider *key_info)
+QUICContext::QUICContext(QUICRTTProvider *rtt, QUICConnectionInfoProvider *info, QUICPacketProtectionKeyInfoProvider *key_info,
+ QUICPathManager *path_manager)
: _key_info(key_info),
_connection_info(info),
_rtt_provider(rtt),
+ _path_manager(path_manager),
_ld_config(std::make_unique<QUICLDConfigQCP>(_config)),
_cc_config(std::make_unique<QUICCCConfigQCP>(_config))
{
}
QUICConnectionInfoProvider *
-QUICContextImpl::connection_info() const
+QUICContext::connection_info() const
{
return _connection_info;
}
QUICConfig::scoped_config
-QUICContextImpl::config() const
+QUICContext::config() const
{
return _config;
}
QUICPacketProtectionKeyInfoProvider *
-QUICContextImpl::key_info() const
+QUICContext::key_info() const
{
return _key_info;
}
QUICRTTProvider *
-QUICContextImpl::rtt_provider() const
+QUICContext::rtt_provider() const
{
return _rtt_provider;
}
QUICLDConfig &
-QUICContextImpl::ld_config() const
+QUICContext::ld_config() const
{
return *_ld_config;
}
QUICCCConfig &
-QUICContextImpl::cc_config() const
+QUICContext::cc_config() const
{
return *_cc_config;
}
+
+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 57e6c0b..31e494c 100644
--- a/iocore/net/quic/QUICContext.h
+++ b/iocore/net/quic/QUICContext.h
@@ -25,60 +25,170 @@
#include "QUICConnection.h"
#include "QUICConfig.h"
+#include "QUICEvents.h"
+#include "QUICCongestionController.h"
class QUICRTTProvider;
class QUICCongestionController;
class QUICPacketProtectionKeyInfoProvider;
+class QUICPathManager;
+class QUICPacketR;
+class QUICPacket;
class QUICNetVConnection;
+struct QUICPacketInfo;
-class QUICContext
-{
-public:
- virtual ~QUICContext(){};
- virtual QUICConnectionInfoProvider *connection_info() const = 0;
- virtual QUICConfig::scoped_config config() const = 0;
-};
-
-class QUICLDContext
+// this class is a connection between the callbacks. it should do something
+// TODO: it should do something
+class QUICCallbackContext
{
-public:
- virtual ~QUICLDContext() {}
- virtual QUICConnectionInfoProvider *connection_info() const = 0;
- virtual QUICLDConfig &ld_config() const = 0;
- virtual QUICPacketProtectionKeyInfoProvider *key_info() const = 0;
};
-class QUICCCContext
+class QUICCallback
{
public:
- virtual ~QUICCCContext() {}
- virtual QUICConnectionInfoProvider *connection_info() const = 0;
- virtual QUICCCConfig &cc_config() const = 0;
- virtual QUICRTTProvider *rtt_provider() const = 0;
+ virtual ~QUICCallback() {}
+
+ // callback on connection close event
+ virtual void connection_close_callback(QUICCallbackContext &){};
+ // 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){};
+ // callback on packet receive event
+ virtual void packet_recv_callback(QUICCallbackContext &, const QUICPacket &p){};
+ // callback on packet acked event
+ virtual void cc_metrics_update_callback(QUICCallbackContext &, uint64_t congestion_window, uint64_t bytes_in_flight,
+ uint64_t sshresh){};
+ // callback on packet receive event
+ virtual void frame_packetize_callback(QUICCallbackContext &, const QUICFrame &p){};
+ // callback on packet receive event
+ virtual void frame_recv_callback(QUICCallbackContext &, const QUICFrame &p){};
+ // callback on packet receive event
+ virtual void congestion_state_updated_callback(QUICCallbackContext &, QUICCongestionController::State p){};
};
-class QUICContextImpl : public QUICContext, public QUICCCContext, public QUICLDContext
+class QUICContext
{
public:
- QUICContextImpl(QUICRTTProvider *rtt, QUICConnectionInfoProvider *info, QUICPacketProtectionKeyInfoProvider *key_info);
-
- virtual QUICConnectionInfoProvider *connection_info() const override;
- virtual QUICConfig::scoped_config config() const override;
- virtual QUICRTTProvider *rtt_provider() const override;
+ QUICContext(QUICRTTProvider *rtt, QUICConnectionInfoProvider *info, QUICPacketProtectionKeyInfoProvider *key_info,
+ QUICPathManager *path_manager);
- // TODO should be more abstract
- virtual QUICPacketProtectionKeyInfoProvider *key_info() const override;
-
- virtual QUICLDConfig &ld_config() const override;
- virtual QUICCCConfig &cc_config() const override;
+ virtual ~QUICContext(){};
+ virtual QUICConnectionInfoProvider *connection_info() const;
+ virtual QUICConfig::scoped_config config() const;
+ virtual QUICLDConfig &ld_config() const;
+ virtual QUICPacketProtectionKeyInfoProvider *key_info() const;
+ virtual QUICCCConfig &cc_config() const;
+ virtual QUICRTTProvider *rtt_provider() const;
+ virtual QUICPathManager *path_manager() const;
+
+ // regist a callback which will be called when specifed event happen.
+ void
+ regist_callback(std::shared_ptr<QUICCallback> cbs)
+ {
+ this->_callbacks.push_back(cbs);
+ }
+
+ enum class CallbackEvent : uint8_t {
+ PACKET_LOST,
+ PACKET_SEND,
+ FRAME_PACKETIZE,
+ PACKET_RECV,
+ FRAME_RECV,
+ METRICS_UPDATE,
+ CONNECTION_CLOSE,
+ CONGESTION_STATE_CHANGED,
+ };
+
+ // FIXME stupid trigger should be fix in more smart way.
+ void
+ trigger(CallbackEvent e, const QUICPacket *p = nullptr)
+ {
+ QUICCallbackContext ctx;
+ switch (e) {
+ case CallbackEvent::PACKET_RECV:
+ for (auto &&it : this->_callbacks) {
+ it->packet_recv_callback(ctx, *p);
+ }
+ break;
+ case CallbackEvent::PACKET_SEND:
+ for (auto &&it : this->_callbacks) {
+ it->packet_send_callback(ctx, *p);
+ }
+ break;
+ case CallbackEvent::CONNECTION_CLOSE:
+ for (auto &&it : this->_callbacks) {
+ it->connection_close_callback(ctx);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ void
+ trigger(CallbackEvent e, const QUICPacketInfo &p)
+ {
+ QUICCallbackContext ctx;
+ for (auto &&it : this->_callbacks) {
+ it->packet_lost_callback(ctx, p);
+ }
+ }
+
+ void
+ trigger(CallbackEvent e, uint64_t congestion_window, uint64_t bytes_in_flight, uint64_t sshresh)
+ {
+ QUICCallbackContext ctx;
+ for (auto &&it : this->_callbacks) {
+ it->cc_metrics_update_callback(ctx, congestion_window, bytes_in_flight, sshresh);
+ }
+ }
+
+ void
+ trigger(CallbackEvent e, QUICCongestionController::State state)
+ {
+ QUICCallbackContext ctx;
+ for (auto &&it : this->_callbacks) {
+ it->congestion_state_updated_callback(ctx, state);
+ }
+ }
+
+ void
+ trigger(CallbackEvent e, const QUICFrame &frame)
+ {
+ QUICCallbackContext ctx;
+ switch (e) {
+ case CallbackEvent::FRAME_PACKETIZE:
+
+ for (auto &&it : this->_callbacks) {
+ it->frame_packetize_callback(ctx, frame);
+ }
+ break;
+
+ case CallbackEvent::FRAME_RECV:
+ for (auto &&it : this->_callbacks) {
+ it->frame_recv_callback(ctx, frame);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+protected:
+ // For Mock
+ QUICContext() {}
private:
QUICConfig::scoped_config _config;
QUICPacketProtectionKeyInfoProvider *_key_info = nullptr;
QUICConnectionInfoProvider *_connection_info = nullptr;
QUICRTTProvider *_rtt_provider = nullptr;
+ QUICPathManager *_path_manager = nullptr;
std::unique_ptr<QUICLDConfig> _ld_config = nullptr;
std::unique_ptr<QUICCCConfig> _cc_config = nullptr;
+
+ std::vector<std::shared_ptr<QUICCallback>> _callbacks;
};
diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc
index bf9d2d8..6a75032 100644
--- a/iocore/net/quic/QUICDebugNames.cc
+++ b/iocore/net/quic/QUICDebugNames.cc
@@ -90,6 +90,8 @@ QUICDebugNames::frame_type(QUICFrameType type)
return "RETIRE_CONNECTION_ID";
case QUICFrameType::NEW_TOKEN:
return "NEW_TOKEN";
+ case QUICFrameType::HANDSHAKE_DONE:
+ return "HANDSHAKE_DONE";
case QUICFrameType::UNKNOWN:
default:
return "UNKNOWN";
@@ -131,8 +133,12 @@ QUICDebugNames::error_code(uint16_t code)
return "FRAME_ENCODING_ERROR";
case static_cast<uint16_t>(QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR):
return "TRANSPORT_PARAMETER_ERROR";
+ case static_cast<uint16_t>(QUICTransErrorCode::CONNECTION_ID_LIMIT_ERROR):
+ return "CONNECTION_ID_LIMIT_ERROR";
case static_cast<uint16_t>(QUICTransErrorCode::PROTOCOL_VIOLATION):
return "PROTOCOL_VIOLATION";
+ case static_cast<uint16_t>(QUICTransErrorCode::INVALID_TOKEN):
+ return "INVALID_TOKEN";
case static_cast<uint16_t>(QUICTransErrorCode::CRYPTO_BUFFER_EXCEEDED):
return "CRYPTO_BUFFER_EXCEEDED";
default:
@@ -179,8 +185,8 @@ QUICDebugNames::transport_parameter_id(QUICTransportParameterId id)
return "INITIAL_MAX_DATA";
case QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI:
return "INITIAL_MAX_STREAMS_BIDI";
- case QUICTransportParameterId::IDLE_TIMEOUT:
- return "IDLE_TIMEOUT";
+ case QUICTransportParameterId::MAX_IDLE_TIMEOUT:
+ return "MAX_IDLE_TIMEOUT";
case QUICTransportParameterId::PREFERRED_ADDRESS:
return "PREFERRED_ADDRESS";
case QUICTransportParameterId::MAX_PACKET_SIZE:
diff --git a/iocore/net/quic/QUICEvents.h b/iocore/net/quic/QUICEvents.h
index c758249..50362e8 100644
--- a/iocore/net/quic/QUICEvents.h
+++ b/iocore/net/quic/QUICEvents.h
@@ -35,4 +35,5 @@ enum {
QUIC_EVENT_ACK_PERIODIC,
QUIC_EVENT_SHUTDOWN,
QUIC_EVENT_LD_SHUTDOWN,
+ QUIC_EVENT_STATELESS_RESET,
};
diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc
index b5275d0..60e665c 100644
--- a/iocore/net/quic/QUICFlowController.cc
+++ b/iocore/net/quic/QUICFlowController.cc
@@ -120,8 +120,17 @@ QUICFlowController::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint
if (this->_should_create_frame) {
frame = this->_create_frame(buf);
- if (frame && frame->size() <= maximum_frame_size) {
- this->_should_create_frame = false;
+ if (frame) {
+ if (frame->size() <= maximum_frame_size) {
+ this->_should_create_frame = false;
+ QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc());
+ info->type = frame->type();
+ info->level = QUICEncryptionLevel::NONE;
+ *(reinterpret_cast<QUICOffset *>(info->data)) = this->_limit;
+ this->_records_frame(frame->id(), std::move(info));
+ } else {
+ frame = nullptr;
+ }
}
}
@@ -223,48 +232,23 @@ QUICLocalFlowController::_need_to_forward_limit()
QUICFrame *
QUICRemoteConnectionFlowController::_create_frame(uint8_t *buf)
{
- auto frame = QUICFrameFactory::create_data_blocked_frame(buf, this->_offset, this->_issue_frame_id(), this);
- QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc());
- info->type = frame->type();
- info->level = QUICEncryptionLevel::NONE;
- *(reinterpret_cast<QUICOffset *>(info->data)) = this->_offset;
- this->_records_frame(frame->id(), std::move(info));
- return frame;
+ return QUICFrameFactory::create_data_blocked_frame(buf, this->_offset, this->_issue_frame_id(), this);
}
QUICFrame *
QUICLocalConnectionFlowController::_create_frame(uint8_t *buf)
{
- auto frame = QUICFrameFactory::create_max_data_frame(buf, this->_limit, this->_issue_frame_id(), this);
- QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc());
- info->type = frame->type();
- info->level = QUICEncryptionLevel::NONE;
- *(reinterpret_cast<QUICOffset *>(info->data)) = this->_limit;
- this->_records_frame(frame->id(), std::move(info));
- return frame;
+ return QUICFrameFactory::create_max_data_frame(buf, this->_limit, this->_issue_frame_id(), this);
}
QUICFrame *
QUICRemoteStreamFlowController::_create_frame(uint8_t *buf)
{
- auto frame =
- QUICFrameFactory::create_stream_data_blocked_frame(buf, this->_stream_id, this->_offset, this->_issue_frame_id(), this);
- QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc());
- info->type = frame->type();
- info->level = QUICEncryptionLevel::NONE;
- *(reinterpret_cast<QUICOffset *>(info->data)) = this->_offset;
- this->_records_frame(frame->id(), std::move(info));
- return frame;
+ return QUICFrameFactory::create_stream_data_blocked_frame(buf, this->_stream_id, this->_offset, this->_issue_frame_id(), this);
}
QUICFrame *
QUICLocalStreamFlowController::_create_frame(uint8_t *buf)
{
- auto frame = QUICFrameFactory::create_max_stream_data_frame(buf, this->_stream_id, this->_limit, this->_issue_frame_id(), this);
- QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc());
- info->type = frame->type();
- info->level = QUICEncryptionLevel::NONE;
- *(reinterpret_cast<QUICOffset *>(info->data)) = this->_limit;
- this->_records_frame(frame->id(), std::move(info));
- return frame;
+ return QUICFrameFactory::create_max_stream_data_frame(buf, this->_stream_id, this->_limit, this->_issue_frame_id(), this);
}
diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc
index 68f03e3..1bffae3 100644
--- a/iocore/net/quic/QUICFrame.cc
+++ b/iocore/net/quic/QUICFrame.cc
@@ -46,7 +46,7 @@ read_varint(uint8_t *&pos, size_t len, uint64_t &field, size_t &field_len)
return false;
}
- field = QUICIntUtil::read_QUICVariableInt(pos);
+ field = QUICIntUtil::read_QUICVariableInt(pos, len);
pos += field_len;
return true;
}
@@ -63,10 +63,10 @@ QUICFrame::ack_eliciting() const
{
auto type = this->type();
- return type != QUICFrameType::PADDING && type != QUICFrameType::ACK;
+ return type != QUICFrameType::PADDING && type != QUICFrameType::ACK && type != QUICFrameType::CONNECTION_CLOSE;
}
-const QUICPacket *
+const QUICPacketR *
QUICFrame::packet() const
{
return this->_packet;
@@ -112,7 +112,7 @@ QUICFrame::type(const uint8_t *buf)
buf[0] < static_cast<uint8_t>(QUICFrameType::NEW_CONNECTION_ID)) {
return QUICFrameType::STREAMS_BLOCKED;
} else if (static_cast<uint8_t>(QUICFrameType::CONNECTION_CLOSE) <= buf[0] &&
- buf[0] < static_cast<uint8_t>(QUICFrameType::UNKNOWN)) {
+ buf[0] < static_cast<uint8_t>(QUICFrameType::HANDSHAKE_DONE)) {
return QUICFrameType::CONNECTION_CLOSE;
} else {
return static_cast<QUICFrameType>(buf[0]);
@@ -147,7 +147,7 @@ QUICStreamFrame::QUICStreamFrame(Ptr<IOBufferBlock> &block, QUICStreamId stream_
{
}
-QUICStreamFrame::QUICStreamFrame(const uint8_t *buf, size_t len, const QUICPacket *packet) : QUICFrame(0, nullptr, packet)
+QUICStreamFrame::QUICStreamFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet) : QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
@@ -164,7 +164,7 @@ QUICStreamFrame::QUICStreamFrame(const QUICStreamFrame &o)
}
void
-QUICStreamFrame::parse(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICStreamFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
@@ -392,7 +392,7 @@ QUICCryptoFrame::QUICCryptoFrame(Ptr<IOBufferBlock> &block, QUICOffset offset, Q
{
}
-QUICCryptoFrame::QUICCryptoFrame(const uint8_t *buf, size_t len, const QUICPacket *packet) : QUICFrame(0, nullptr, packet)
+QUICCryptoFrame::QUICCryptoFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet) : QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
@@ -403,7 +403,7 @@ QUICCryptoFrame::QUICCryptoFrame(const QUICCryptoFrame &o)
}
void
-QUICCryptoFrame::parse(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICCryptoFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
@@ -541,13 +541,29 @@ QUICCryptoFrame::data() const
// ACK frame
//
-QUICAckFrame::QUICAckFrame(const uint8_t *buf, size_t len, const QUICPacket *packet) : QUICFrame(0, nullptr, packet)
+std::set<QUICAckFrame::PacketNumberRange>
+QUICAckFrame::ranges() const
+{
+ std::set<QUICAckFrame::PacketNumberRange> numbers;
+ QUICPacketNumber x = this->largest_acknowledged();
+ numbers.insert({x, static_cast<uint64_t>(x) - this->ack_block_section()->first_ack_block()});
+ x -= this->ack_block_section()->first_ack_block() + 1;
+ for (auto &&block : *(this->ack_block_section())) {
+ x -= block.gap() + 1;
+ numbers.insert({x, static_cast<uint64_t>(x) - block.length()});
+ x -= block.length() + 1;
+ }
+
+ return numbers;
+}
+
+QUICAckFrame::QUICAckFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet) : QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
-QUICAckFrame::parse(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICAckFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
@@ -997,13 +1013,13 @@ QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode
{
}
-QUICRstStreamFrame::QUICRstStreamFrame(const uint8_t *buf, size_t len, const QUICPacket *packet) : QUICFrame(0, nullptr, packet)
+QUICRstStreamFrame::QUICRstStreamFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet) : QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
-QUICRstStreamFrame::parse(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICRstStreamFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
@@ -1128,13 +1144,13 @@ QUICRstStreamFrame::final_offset() const
// PING frame
//
-QUICPingFrame::QUICPingFrame(const uint8_t *buf, size_t len, const QUICPacket *packet) : QUICFrame(0, nullptr, packet)
+QUICPingFrame::QUICPingFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet) : QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
-QUICPingFrame::parse(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICPingFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
this->_reset();
this->_packet = packet;
@@ -1179,13 +1195,13 @@ QUICPingFrame::to_io_buffer_block(size_t limit) const
//
// PADDING frame
//
-QUICPaddingFrame::QUICPaddingFrame(const uint8_t *buf, size_t len, const QUICPacket *packet) : QUICFrame(0, nullptr, packet)
+QUICPaddingFrame::QUICPaddingFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet) : QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
-QUICPaddingFrame::parse(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICPaddingFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
@@ -1265,7 +1281,7 @@ QUICConnectionCloseFrame::QUICConnectionCloseFrame(uint64_t error_code, uint64_t
{
}
-QUICConnectionCloseFrame::QUICConnectionCloseFrame(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICConnectionCloseFrame::QUICConnectionCloseFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
: QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
@@ -1286,7 +1302,7 @@ QUICConnectionCloseFrame::_reset()
}
void
-QUICConnectionCloseFrame::parse(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICConnectionCloseFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
@@ -1488,13 +1504,13 @@ QUICMaxDataFrame::_reset()
this->_size = 0;
}
-QUICMaxDataFrame::QUICMaxDataFrame(const uint8_t *buf, size_t len, const QUICPacket *packet) : QUICFrame(0, nullptr, packet)
+QUICMaxDataFrame::QUICMaxDataFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet) : QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
-QUICMaxDataFrame::parse(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICMaxDataFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
@@ -1588,14 +1604,14 @@ QUICMaxStreamDataFrame::_reset()
this->_size = 0;
}
-QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
: QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
-QUICMaxStreamDataFrame::parse(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICMaxStreamDataFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
@@ -1701,13 +1717,13 @@ QUICMaxStreamsFrame::_reset()
this->_size = 0;
}
-QUICMaxStreamsFrame::QUICMaxStreamsFrame(const uint8_t *buf, size_t len, const QUICPacket *packet) : QUICFrame(0, nullptr, packet)
+QUICMaxStreamsFrame::QUICMaxStreamsFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet) : QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
-QUICMaxStreamsFrame::parse(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICMaxStreamsFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
@@ -1775,7 +1791,8 @@ QUICMaxStreamsFrame::maximum_streams() const
//
// DATA_BLOCKED frame
//
-QUICDataBlockedFrame::QUICDataBlockedFrame(const uint8_t *buf, size_t len, const QUICPacket *packet) : QUICFrame(0, nullptr, packet)
+QUICDataBlockedFrame::QUICDataBlockedFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
+ : QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
@@ -1792,7 +1809,7 @@ QUICDataBlockedFrame::_reset()
}
void
-QUICDataBlockedFrame::parse(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICDataBlockedFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
@@ -1866,7 +1883,7 @@ QUICDataBlockedFrame::offset() const
//
// STREAM_DATA_BLOCKED frame
//
-QUICStreamDataBlockedFrame::QUICStreamDataBlockedFrame(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICStreamDataBlockedFrame::QUICStreamDataBlockedFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
: QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
@@ -1885,7 +1902,7 @@ QUICStreamDataBlockedFrame::_reset()
}
void
-QUICStreamDataBlockedFrame::parse(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICStreamDataBlockedFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
@@ -1974,7 +1991,7 @@ QUICStreamDataBlockedFrame::offset() const
//
// STREAMS_BLOCKED frame
//
-QUICStreamIdBlockedFrame::QUICStreamIdBlockedFrame(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICStreamIdBlockedFrame::QUICStreamIdBlockedFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
: QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
@@ -1992,7 +2009,7 @@ QUICStreamIdBlockedFrame::_reset()
}
void
-QUICStreamIdBlockedFrame::parse(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICStreamIdBlockedFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
@@ -2060,7 +2077,7 @@ QUICStreamIdBlockedFrame::stream_id() const
//
// NEW_CONNECTION_ID frame
//
-QUICNewConnectionIdFrame::QUICNewConnectionIdFrame(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICNewConnectionIdFrame::QUICNewConnectionIdFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
: QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
@@ -2080,7 +2097,7 @@ QUICNewConnectionIdFrame::_reset()
}
void
-QUICNewConnectionIdFrame::parse(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICNewConnectionIdFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
@@ -2190,11 +2207,10 @@ QUICNewConnectionIdFrame::to_io_buffer_block(size_t limit) const
int
QUICNewConnectionIdFrame::debug_msg(char *msg, size_t msg_len) const
{
- char cid_str[QUICConnectionId::MAX_HEX_STR_LENGTH];
- this->connection_id().hex(cid_str, QUICConnectionId::MAX_HEX_STR_LENGTH);
-
- return snprintf(msg, msg_len, "NEW_CONNECTION_ID size=%zu seq=%" PRIu64 " rpt=%" PRIu64 " cid=0x%s", this->size(),
- this->sequence(), this->retire_prior_to(), cid_str);
+ return snprintf(msg, msg_len, "NEW_CONNECTION_ID size=%zu seq=%" PRIu64 " rpt=%" PRIu64 " cid=0x%s srt=%02x%02x%02x%02x",
+ this->size(), this->sequence(), this->retire_prior_to(), this->connection_id().hex().c_str(),
+ this->stateless_reset_token().buf()[0], this->stateless_reset_token().buf()[1],
+ this->stateless_reset_token().buf()[2], this->stateless_reset_token().buf()[3]);
}
uint64_t
@@ -2243,13 +2259,14 @@ QUICStopSendingFrame::_reset()
this->_size = 0;
}
-QUICStopSendingFrame::QUICStopSendingFrame(const uint8_t *buf, size_t len, const QUICPacket *packet) : QUICFrame(0, nullptr, packet)
+QUICStopSendingFrame::QUICStopSendingFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
+ : QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
-QUICStopSendingFrame::parse(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICStopSendingFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
@@ -2336,7 +2353,7 @@ QUICStopSendingFrame::stream_id() const
//
// PATH_CHALLENGE frame
//
-QUICPathChallengeFrame::QUICPathChallengeFrame(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICPathChallengeFrame::QUICPathChallengeFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
: QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
@@ -2353,7 +2370,7 @@ QUICPathChallengeFrame::_reset()
}
void
-QUICPathChallengeFrame::parse(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICPathChallengeFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
@@ -2435,7 +2452,7 @@ QUICPathChallengeFrame::data() const
//
// PATH_RESPONSE frame
//
-QUICPathResponseFrame::QUICPathResponseFrame(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICPathResponseFrame::QUICPathResponseFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
: QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
@@ -2478,7 +2495,7 @@ QUICPathResponseFrame::to_io_buffer_block(size_t limit) const
}
void
-QUICPathResponseFrame::parse(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICPathResponseFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
@@ -2530,7 +2547,7 @@ QUICPathResponseFrame::data() const
//
// QUICNewTokenFrame
//
-QUICNewTokenFrame::QUICNewTokenFrame(const uint8_t *buf, size_t len, const QUICPacket *packet) : QUICFrame(0, nullptr, packet)
+QUICNewTokenFrame::QUICNewTokenFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet) : QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
@@ -2548,7 +2565,7 @@ QUICNewTokenFrame::_reset()
}
void
-QUICNewTokenFrame::parse(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICNewTokenFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
@@ -2632,7 +2649,7 @@ QUICNewTokenFrame::token() const
//
// RETIRE_CONNECTION_ID frame
//
-QUICRetireConnectionIdFrame::QUICRetireConnectionIdFrame(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICRetireConnectionIdFrame::QUICRetireConnectionIdFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
: QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
@@ -2651,7 +2668,7 @@ QUICRetireConnectionIdFrame::_reset()
}
void
-QUICRetireConnectionIdFrame::parse(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICRetireConnectionIdFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
@@ -2723,6 +2740,59 @@ QUICRetireConnectionIdFrame::seq_num() const
}
//
+// HANDSHAKE_DONE frame
+//
+
+QUICHandshakeDoneFrame::QUICHandshakeDoneFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
+ : QUICFrame(0, nullptr, packet)
+{
+ this->parse(buf, len, packet);
+}
+
+void
+QUICHandshakeDoneFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
+{
+ this->_reset();
+ this->_packet = packet;
+ this->_valid = true;
+ this->_size = 1;
+}
+
+QUICFrameType
+QUICHandshakeDoneFrame::type() const
+{
+ return QUICFrameType::HANDSHAKE_DONE;
+}
+
+size_t
+QUICHandshakeDoneFrame::size() const
+{
+ return 1;
+}
+
+Ptr<IOBufferBlock>
+QUICHandshakeDoneFrame::to_io_buffer_block(size_t limit) const
+{
+ Ptr<IOBufferBlock> block;
+ size_t n = 0;
+
+ if (limit < this->size()) {
+ return block;
+ }
+
+ block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ block->alloc(iobuffer_size_to_index(this->size(), BUFFER_SIZE_INDEX_32K));
+ uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
+
+ // Type
+ block_start[0] = static_cast<uint8_t>(QUICFrameType::HANDSHAKE_DONE);
+ n += 1;
+
+ block->fill(n);
+ return block;
+}
+
+//
// UNKNOWN
//
QUICFrameType
@@ -2746,7 +2816,7 @@ QUICUnknownFrame::to_io_buffer_block(size_t limit) const
}
void
-QUICUnknownFrame::parse(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICUnknownFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
this->_packet = packet;
}
@@ -2762,7 +2832,7 @@ QUICUnknownFrame::debug_msg(char *msg, size_t msg_len) const
//
QUICFrame *
-QUICFrameFactory::create(uint8_t *buf, const uint8_t *src, size_t len, const QUICPacket *packet)
+QUICFrameFactory::create(uint8_t *buf, const uint8_t *src, size_t len, const QUICPacketR *packet)
{
switch (QUICFrame::type(src)) {
case QUICFrameType::STREAM:
@@ -2822,6 +2892,9 @@ QUICFrameFactory::create(uint8_t *buf, const uint8_t *src, size_t len, const QUI
case QUICFrameType::RETIRE_CONNECTION_ID:
new (buf) QUICRetireConnectionIdFrame(src, len, packet);
return reinterpret_cast<QUICFrame *>(buf);
+ case QUICFrameType::HANDSHAKE_DONE:
+ new (buf) QUICHandshakeDoneFrame(src, len, packet);
+ return reinterpret_cast<QUICFrame *>(buf);
default:
// Unknown frame
Debug("quic_frame_factory", "Unknown frame type %x", src[0]);
@@ -2830,7 +2903,7 @@ QUICFrameFactory::create(uint8_t *buf, const uint8_t *src, size_t len, const QUI
}
const QUICFrame &
-QUICFrameFactory::fast_create(const uint8_t *buf, size_t len, const QUICPacket *packet)
+QUICFrameFactory::fast_create(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
if (QUICFrame::type(buf) == QUICFrameType::UNKNOWN) {
return this->_unknown_frame;
@@ -3024,6 +3097,13 @@ QUICFrameFactory::create_retire_connection_id_frame(uint8_t *buf, uint64_t seq_n
return reinterpret_cast<QUICRetireConnectionIdFrame *>(buf);
}
+QUICHandshakeDoneFrame *
+QUICFrameFactory::create_handshake_done_frame(uint8_t *buf, QUICFrameId id, QUICFrameGenerator *owner)
+{
+ new (buf) QUICHandshakeDoneFrame(id, owner);
+ return reinterpret_cast<QUICHandshakeDoneFrame *>(buf);
+}
+
QUICFrameId
QUICFrameInfo::id() const
{
diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h
index 8d78510..e933e68 100644
--- a/iocore/net/quic/QUICFrame.h
+++ b/iocore/net/quic/QUICFrame.h
@@ -30,13 +30,14 @@
#include "I_IOBuffer.h"
#include <vector>
#include <iterator>
+#include <set>
#include "QUICTypes.h"
class QUICFrame;
class QUICStreamFrame;
class QUICCryptoFrame;
-class QUICPacket;
+class QUICPacketR;
class QUICFrameGenerator;
using QUICFrameId = uint64_t;
@@ -57,16 +58,16 @@ public:
virtual bool is_flow_controlled() const;
virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const = 0;
virtual int debug_msg(char *msg, size_t msg_len) const;
- virtual void parse(const uint8_t *buf, size_t len, const QUICPacket *packet){};
+ virtual void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet){};
virtual QUICFrameGenerator *generated_by();
bool valid() const;
bool ack_eliciting() const;
- const QUICPacket *packet() const;
+ const QUICPacketR *packet() const;
LINK(QUICFrame, link);
protected:
virtual void _reset(){};
- QUICFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr, const QUICPacket *packet = nullptr)
+ QUICFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr, const QUICPacketR *packet = nullptr)
: _id(id), _owner(owner), _packet(packet)
{
}
@@ -74,7 +75,7 @@ protected:
bool _valid = false;
QUICFrameId _id = 0;
QUICFrameGenerator *_owner = nullptr;
- const QUICPacket *_packet = nullptr;
+ const QUICPacketR *_packet = nullptr;
};
//
@@ -85,7 +86,7 @@ class QUICStreamFrame : public QUICFrame
{
public:
QUICStreamFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {}
- QUICStreamFrame(const uint8_t *buf, size_t len, const QUICPacket *packet = nullptr);
+ QUICStreamFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet = nullptr);
QUICStreamFrame(Ptr<IOBufferBlock> &block, QUICStreamId streamid, QUICOffset offset, bool last = false,
bool has_offset_field = true, bool has_length_field = true, QUICFrameId id = 0,
QUICFrameGenerator *owner = nullptr);
@@ -96,7 +97,7 @@ public:
virtual bool is_flow_controlled() const override;
virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const override;
virtual int debug_msg(char *msg, size_t msg_len) const override;
- virtual void parse(const uint8_t *buf, size_t len, const QUICPacket *packet) override;
+ virtual void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet) override;
QUICStreamId stream_id() const;
QUICOffset offset() const;
@@ -131,7 +132,7 @@ class QUICCryptoFrame : public QUICFrame
{
public:
QUICCryptoFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {}
- QUICCryptoFrame(const uint8_t *buf, size_t len, const QUICPacket *packet = nullptr);
+ QUICCryptoFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet = nullptr);
QUICCryptoFrame(Ptr<IOBufferBlock> &block, QUICOffset offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr);
QUICCryptoFrame(const QUICCryptoFrame &o);
@@ -139,7 +140,7 @@ public:
virtual size_t size() const override;
virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const override;
virtual int debug_msg(char *msg, size_t msg_len) const override;
- virtual void parse(const uint8_t *buf, size_t len, const QUICPacket *packet) override;
+ virtual void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet) override;
QUICOffset offset() const;
uint64_t data_length() const;
@@ -265,9 +266,10 @@ public:
};
QUICAckFrame(QUICFrameId id = 0) : QUICFrame(id) {}
- QUICAckFrame(const uint8_t *buf, size_t len, const QUICPacket *packet = nullptr);
+ QUICAckFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet = nullptr);
QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, QUICFrameId id = 0,
QUICFrameGenerator *owner = nullptr);
+ std::set<PacketNumberRange> ranges() const;
// There's no reasont restrict copy, but we need to write the copy constructor. Otherwise it will crash on destruct.
QUICAckFrame(const QUICAckFrame &) = delete;
@@ -276,7 +278,7 @@ public:
virtual QUICFrameType type() const override;
virtual size_t size() const override;
virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const override;
- virtual void parse(const uint8_t *buf, size_t len, const QUICPacket *packet) override;
+ virtual void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet) override;
virtual int debug_msg(char *msg, size_t msg_len) const override;
QUICPacketNumber largest_acknowledged() const;
@@ -304,7 +306,7 @@ class QUICRstStreamFrame : public QUICFrame
{
public:
QUICRstStreamFrame(QUICFrameId id = 0) : QUICFrame(id) {}
- QUICRstStreamFrame(const uint8_t *buf, size_t len, const QUICPacket *packet = nullptr);
+ QUICRstStreamFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet = nullptr);
QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, QUICFrameId id = 0,
QUICFrameGenerator *owner = nullptr);
@@ -312,7 +314,7 @@ public:
virtual size_t size() const override;
virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const override;
virtual int debug_msg(char *msg, size_t msg_len) const override;
- virtual void parse(const uint8_t *buf, size_t len, const QUICPacket *packet) override;
+ virtual void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet) override;
QUICStreamId stream_id() const;
QUICAppErrorCode error_code() const;
@@ -334,11 +336,11 @@ class QUICPingFrame : public QUICFrame
{
public:
QUICPingFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {}
- QUICPingFrame(const uint8_t *buf, size_t len, const QUICPacket *packet = nullptr);
+ QUICPingFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet = nullptr);
virtual QUICFrameType type() const override;
virtual size_t size() const override;
virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const override;
- virtual void parse(const uint8_t *buf, size_t len, const QUICPacket *packet) override;
+ virtual void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet) override;
private:
};
@@ -351,12 +353,12 @@ class QUICPaddingFrame : public QUICFrame
{
public:
QUICPaddingFrame(size_t size) : _size(size) {}
- QUICPaddingFrame(const uint8_t *buf, size_t len, const QUICPacket *packet = nullptr);
+ QUICPaddingFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet = nullptr);
virtual QUICFrameType type() const override;
virtual size_t size() const override;
virtual bool is_probing_frame() const override;
virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const override;
- virtual void parse(const uint8_t *buf, size_t len, const QUICPacket *packet) override;
+ virtual void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet) override;
private:
// padding frame is a resident of padding frames
@@ -372,7 +374,7 @@ class QUICConnectionCloseFrame : public QUICFrame
{
public:
QUICConnectionCloseFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {}
- QUICConnectionCloseFrame(const uint8_t *buf, size_t len, const QUICPacket *packet = nullptr);
+ QUICConnectionCloseFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet = nullptr);
// Constructor for transport error codes
QUICConnectionCloseFrame(uint64_t error_code, QUICFrameType frame_type, uint64_t reason_phrase_length, const char *reason_phrase,
QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr);
@@ -383,7 +385,7 @@ public:
virtual size_t size() const override;
virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const override;
virtual int debug_msg(char *msg, size_t msg_len) const override;
- virtual void parse(const uint8_t *buf, size_t len, const QUICPacket *packet) override;
+ virtual void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet) override;
uint16_t error_code() const;
QUICFrameType frame_type() const;
@@ -408,13 +410,13 @@ class QUICMaxDataFrame : public QUICFrame
{
public:
QUICMaxDataFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {}
- QUICMaxDataFrame(const uint8_t *buf, size_t len, const QUICPacket *packet = nullptr);
+ QUICMaxDataFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet = nullptr);
QUICMaxDataFrame(uint64_t maximum_data, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr);
virtual QUICFrameType type() const override;
virtual size_t size() const override;
virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const override;
virtual int debug_msg(char *msg, size_t msg_len) const override;
- virtual void parse(const uint8_t *buf, size_t len, const QUICPacket *packet) override;
+ virtual void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet) override;
uint64_t maximum_data() const;
@@ -432,12 +434,12 @@ class QUICMaxStreamDataFrame : public QUICFrame
{
public:
QUICMaxStreamDataFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {}
- QUICMaxStreamDataFrame(const uint8_t *buf, size_t len, const QUICPacket *packet = nullptr);
+ QUICMaxStreamDataFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet = nullptr);
QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data, QUICFrameId id = 0,
QUICFrameGenerator *owner = nullptr);
virtual QUICFrameType type() const override;
virtual size_t size() const override;
- virtual void parse(const uint8_t *buf, size_t len, const QUICPacket *packet) override;
+ virtual void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet) override;
virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const override;
virtual int debug_msg(char *msg, size_t msg_len) const override;
@@ -459,12 +461,12 @@ class QUICMaxStreamsFrame : public QUICFrame
{
public:
QUICMaxStreamsFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {}
- QUICMaxStreamsFrame(const uint8_t *buf, size_t len, const QUICPacket *packet = nullptr);
+ QUICMaxStreamsFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet = nullptr);
QUICMaxStreamsFrame(QUICStreamId maximum_streams, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr);
virtual QUICFrameType type() const override;
virtual size_t size() const override;
virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const override;
- virtual void parse(const uint8_t *buf, size_t len, const QUICPacket *packet) override;
+ virtual void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet) override;
uint64_t maximum_streams() const;
private:
@@ -480,13 +482,13 @@ class QUICDataBlockedFrame : public QUICFrame
{
public:
QUICDataBlockedFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {}
- QUICDataBlockedFrame(const uint8_t *buf, size_t len, const QUICPacket *packet = nullptr);
+ QUICDataBlockedFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet = nullptr);
QUICDataBlockedFrame(QUICOffset offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr)
: QUICFrame(id, owner), _offset(offset){};
virtual QUICFrameType type() const override;
virtual size_t size() const override;
- virtual void parse(const uint8_t *buf, size_t len, const QUICPacket *packet) override;
+ virtual void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet) override;
virtual int debug_msg(char *msg, size_t msg_len) const override;
virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const override;
@@ -506,14 +508,14 @@ class QUICStreamDataBlockedFrame : public QUICFrame
{
public:
QUICStreamDataBlockedFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {}
- QUICStreamDataBlockedFrame(const uint8_t *buf, size_t len, const QUICPacket *packet = nullptr);
+ QUICStreamDataBlockedFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet = nullptr);
QUICStreamDataBlockedFrame(QUICStreamId s, QUICOffset o, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr)
: QUICFrame(id, owner), _stream_id(s), _offset(o){};
virtual QUICFrameType type() const override;
virtual size_t size() const override;
virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const override;
- virtual void parse(const uint8_t *buf, size_t len, const QUICPacket *packet) override;
+ virtual void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet) override;
virtual int debug_msg(char *msg, size_t msg_len) const override;
QUICStreamId stream_id() const;
@@ -533,7 +535,7 @@ class QUICStreamIdBlockedFrame : public QUICFrame
{
public:
QUICStreamIdBlockedFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {}
- QUICStreamIdBlockedFrame(const uint8_t *buf, size_t len, const QUICPacket *packet = nullptr);
+ QUICStreamIdBlockedFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet = nullptr);
QUICStreamIdBlockedFrame(QUICStreamId s, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr)
: QUICFrame(id, owner), _stream_id(s)
{
@@ -541,7 +543,7 @@ public:
virtual QUICFrameType type() const override;
virtual size_t size() const override;
virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const override;
- virtual void parse(const uint8_t *buf, size_t len, const QUICPacket *packet) override;
+ virtual void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet) override;
QUICStreamId stream_id() const;
@@ -559,7 +561,7 @@ class QUICNewConnectionIdFrame : public QUICFrame
{
public:
QUICNewConnectionIdFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {}
- QUICNewConnectionIdFrame(const uint8_t *buf, size_t len, const QUICPacket *packet = nullptr);
+ QUICNewConnectionIdFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet = nullptr);
QUICNewConnectionIdFrame(uint64_t seq, uint64_t ret, const QUICConnectionId &cid, QUICStatelessResetToken token,
QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr)
: QUICFrame(id, owner), _sequence(seq), _retire_prior_to(ret), _connection_id(cid), _stateless_reset_token(token){};
@@ -567,7 +569,7 @@ public:
virtual QUICFrameType type() const override;
virtual size_t size() const override;
virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const override;
- virtual void parse(const uint8_t *buf, size_t len, const QUICPacket *packet) override;
+ virtual void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet) override;
virtual int debug_msg(char *msg, size_t msg_len) const override;
uint64_t sequence() const;
@@ -592,13 +594,13 @@ class QUICStopSendingFrame : public QUICFrame
{
public:
QUICStopSendingFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {}
- QUICStopSendingFrame(const uint8_t *buf, size_t len, const QUICPacket *packet = nullptr);
+ QUICStopSendingFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet = nullptr);
QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICFrameId id = 0,
QUICFrameGenerator *owner = nullptr);
virtual QUICFrameType type() const override;
virtual size_t size() const override;
- virtual void parse(const uint8_t *buf, size_t len, const QUICPacket *packet) override;
+ virtual void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet) override;
virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const override;
QUICStreamId stream_id() const;
@@ -620,7 +622,7 @@ class QUICPathChallengeFrame : public QUICFrame
public:
static constexpr uint8_t DATA_LEN = 8;
QUICPathChallengeFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {}
- QUICPathChallengeFrame(const uint8_t *buf, size_t len, const QUICPacket *packet = nullptr);
+ QUICPathChallengeFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet = nullptr);
QUICPathChallengeFrame(ats_unique_buf data, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr)
: QUICFrame(id, owner), _data(std::move(data))
{
@@ -628,7 +630,7 @@ public:
virtual QUICFrameType type() const override;
virtual size_t size() const override;
virtual bool is_probing_frame() const override;
- virtual void parse(const uint8_t *buf, size_t len, const QUICPacket *packet) override;
+ virtual void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet) override;
virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const override;
virtual int debug_msg(char *msg, size_t msg_len) const override;
@@ -649,7 +651,7 @@ class QUICPathResponseFrame : public QUICFrame
public:
static constexpr uint8_t DATA_LEN = 8;
QUICPathResponseFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {}
- QUICPathResponseFrame(const uint8_t *buf, size_t len, const QUICPacket *packet = nullptr);
+ QUICPathResponseFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet = nullptr);
QUICPathResponseFrame(ats_unique_buf data, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr)
: QUICFrame(id, owner), _data(std::move(data))
{
@@ -657,7 +659,7 @@ public:
virtual QUICFrameType type() const override;
virtual size_t size() const override;
virtual bool is_probing_frame() const override;
- virtual void parse(const uint8_t *buf, size_t len, const QUICPacket *packet) override;
+ virtual void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet) override;
virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const override;
virtual int debug_msg(char *msg, size_t msg_len) const override;
@@ -677,7 +679,7 @@ class QUICNewTokenFrame : public QUICFrame
{
public:
QUICNewTokenFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {}
- QUICNewTokenFrame(const uint8_t *buf, size_t len, const QUICPacket *packet = nullptr);
+ QUICNewTokenFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet = nullptr);
QUICNewTokenFrame(ats_unique_buf token, size_t token_length, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr)
: QUICFrame(id, owner), _token_length(token_length), _token(std::move(token))
{
@@ -685,7 +687,7 @@ public:
virtual QUICFrameType type() const override;
virtual size_t size() const override;
virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const override;
- virtual void parse(const uint8_t *buf, size_t len, const QUICPacket *packet) override;
+ virtual void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet) override;
uint64_t token_length() const;
const uint8_t *token() const;
@@ -705,7 +707,7 @@ class QUICRetireConnectionIdFrame : public QUICFrame
{
public:
QUICRetireConnectionIdFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {}
- QUICRetireConnectionIdFrame(const uint8_t *buf, size_t len, const QUICPacket *packet = nullptr);
+ QUICRetireConnectionIdFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet = nullptr);
QUICRetireConnectionIdFrame(uint64_t seq_num, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr)
: QUICFrame(id, owner), _seq_num(seq_num)
{
@@ -713,7 +715,7 @@ public:
virtual QUICFrameType type() const override;
virtual size_t size() const override;
virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const override;
- virtual void parse(const uint8_t *buf, size_t len, const QUICPacket *packet) override;
+ virtual void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet) override;
virtual int debug_msg(char *msg, size_t msg_len) const override;
uint64_t seq_num() const;
@@ -725,15 +727,31 @@ private:
};
//
+// HANDSHAKE_DONE
+//
+
+class QUICHandshakeDoneFrame : public QUICFrame
+{
+public:
+ QUICHandshakeDoneFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {}
+ QUICHandshakeDoneFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet = nullptr);
+ virtual QUICFrameType type() const override;
+ virtual size_t size() const override;
+ virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const override;
+ virtual void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet) override;
+};
+
+//
// UNKNOWN
//
class QUICUnknownFrame : public QUICFrame
{
+public:
QUICFrameType type() const override;
size_t size() const override;
virtual Ptr<IOBufferBlock> to_io_buffer_block(size_t limit) const override;
- void parse(const uint8_t *buf, size_t len, const QUICPacket *packet) override;
+ void parse(const uint8_t *buf, size_t len, const QUICPacketR *packet) override;
int debug_msg(char *msg, size_t msg_len) const override;
};
@@ -746,13 +764,13 @@ public:
/*
* This is used for creating a QUICFrame object based on received data.
*/
- static QUICFrame *create(uint8_t *buf, const uint8_t *src, size_t len, const QUICPacket *packet);
+ static QUICFrame *create(uint8_t *buf, const uint8_t *src, size_t len, const QUICPacketR *packet);
/*
* This works almost the same as create() but it reuses created objects for performance.
* If you create a frame object which has the same frame type that you created before, the object will be reset by new data.
*/
- const QUICFrame &fast_create(const uint8_t *buf, size_t len, const QUICPacket *packet);
+ const QUICFrame &fast_create(const uint8_t *buf, size_t len, const QUICPacketR *packet);
/*
* Creates a STREAM frame.
@@ -879,6 +897,11 @@ public:
*/
static QUICPaddingFrame *create_padding_frame(uint8_t *buf, size_t size, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr);
+ /*
+ * Creates a HANDSHAKE_DONE frame
+ */
+ static QUICHandshakeDoneFrame *create_handshake_done_frame(uint8_t *buf, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr);
+
private:
// FIXME Actual number of frame types is several but some of the values are not sequential.
QUICFrame *_reusable_frames[256] = {nullptr};
diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc
index b807ff5..9509933 100644
--- a/iocore/net/quic/QUICFrameDispatcher.cc
+++ b/iocore/net/quic/QUICFrameDispatcher.cc
@@ -42,8 +42,9 @@ QUICFrameDispatcher::add_handler(QUICFrameHandler *handler)
}
QUICConnectionErrorUPtr
-QUICFrameDispatcher::receive_frames(QUICEncryptionLevel level, const uint8_t *payload, uint16_t size, bool &ack_only,
- bool &is_flow_controlled, bool *has_non_probing_frame, const QUICPacket *packet)
+QUICFrameDispatcher::receive_frames(QUICContext &ctx, QUICEncryptionLevel level, const uint8_t *payload, uint16_t size,
+ bool &ack_only, bool &is_flow_controlled, bool *has_non_probing_frame,
+ const QUICPacketR *packet)
{
uint16_t cursor = 0;
ack_only = true;
@@ -63,6 +64,8 @@ QUICFrameDispatcher::receive_frames(QUICEncryptionLevel level, const uint8_t *pa
QUICFrameType type = frame.type();
+ ctx.trigger(QUICContext::CallbackEvent::FRAME_RECV, frame);
+
if (type == QUICFrameType::STREAM) {
is_flow_controlled = true;
}
diff --git a/iocore/net/quic/QUICFrameDispatcher.h b/iocore/net/quic/QUICFrameDispatcher.h
index e7ce785..435103b 100644
--- a/iocore/net/quic/QUICFrameDispatcher.h
+++ b/iocore/net/quic/QUICFrameDispatcher.h
@@ -28,15 +28,16 @@
#include "QUICConnection.h"
#include "QUICFrame.h"
#include "QUICFrameHandler.h"
+#include "QUICContext.h"
class QUICFrameDispatcher
{
public:
QUICFrameDispatcher(QUICConnectionInfoProvider *info);
- QUICConnectionErrorUPtr receive_frames(QUICEncryptionLevel level, const uint8_t *payload, uint16_t size,
+ QUICConnectionErrorUPtr receive_frames(QUICContext &context, QUICEncryptionLevel level, const uint8_t *payload, uint16_t size,
bool &should_send_ackbool, bool &is_flow_controlled, bool *has_non_probing_frame,
- const QUICPacket *packet);
+ const QUICPacketR *packet);
void add_handler(QUICFrameHandler *handler);
diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc
index c88377f..08c3061 100644
--- a/iocore/net/quic/QUICHandshake.cc
+++ b/iocore/net/quic/QUICHandshake.cc
@@ -27,6 +27,7 @@
#include "QUICEvents.h"
#include "QUICGlobals.h"
+#include "QUICHandshakeProtocol.h"
#include "QUICPacketFactory.h"
#include "QUICVersionNegotiator.h"
#include "QUICConfig.h"
@@ -80,8 +81,6 @@
}
static constexpr int UDP_MAXIMUM_PAYLOAD_SIZE = 65527;
-// TODO: fix size
-static constexpr int MAX_HANDSHAKE_MSG_LEN = 65527;
QUICHandshake::QUICHandshake(QUICConnection *qc, QUICHandshakeProtocol *hsp) : QUICHandshake(qc, hsp, {}, false) {}
@@ -119,7 +118,7 @@ QUICHandshake::start(const QUICTPConfig &tp_config, QUICPacketFactory *packet_fa
}
QUICConnectionErrorUPtr
-QUICHandshake::start(const QUICTPConfig &tp_config, const QUICPacket &initial_packet, QUICPacketFactory *packet_factory,
+QUICHandshake::start(const QUICTPConfig &tp_config, const QUICInitialPacketR &initial_packet, QUICPacketFactory *packet_factory,
const QUICPreferredAddress *pref_addr)
{
// Negotiate version
@@ -143,7 +142,7 @@ QUICHandshake::start(const QUICTPConfig &tp_config, const QUICPacket &initial_pa
}
QUICConnectionErrorUPtr
-QUICHandshake::negotiate_version(const QUICPacket &vn, QUICPacketFactory *packet_factory)
+QUICHandshake::negotiate_version(const QUICVersionNegotiationPacketR &vn, QUICPacketFactory *packet_factory)
{
// Client side only
ink_assert(this->_qc->direction() == NET_VCONNECTION_OUT);
@@ -186,6 +185,16 @@ QUICHandshake::is_completed() const
}
bool
+QUICHandshake::is_confirmed() const
+{
+ if (this->_qc->direction() == NET_VCONNECTION_IN) {
+ return this->is_completed();
+ } else {
+ return this->_is_handshake_done_received;
+ }
+}
+
+bool
QUICHandshake::is_stateless_retry_enabled() const
{
return this->_stateless_retry;
@@ -298,6 +307,7 @@ QUICHandshake::interests()
{
return {
QUICFrameType::CRYPTO,
+ QUICFrameType::HANDSHAKE_DONE,
};
}
@@ -308,8 +318,15 @@ QUICHandshake::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame)
switch (frame.type()) {
case QUICFrameType::CRYPTO:
error = this->_crypto_streams[static_cast<int>(level)].recv(static_cast<const QUICCryptoFrame &>(frame));
- if (error != nullptr) {
- return error;
+ if (error == nullptr) {
+ error = this->do_handshake();
+ }
+ break;
+ case QUICFrameType::HANDSHAKE_DONE:
+ if (this->_qc->direction() == NET_VCONNECTION_IN) {
+ error = std::make_unique<QUICConnectionError>(QUICTransErrorCode::PROTOCOL_VIOLATION);
+ } else {
+ this->_is_handshake_done_received = true;
}
break;
default:
@@ -318,7 +335,7 @@ QUICHandshake::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame)
break;
}
- return this->do_handshake();
+ return error;
}
bool
@@ -328,7 +345,8 @@ QUICHandshake::will_generate_frame(QUICEncryptionLevel level, size_t current_pac
return false;
}
- return this->_crypto_streams[static_cast<int>(level)].will_generate_frame(level, current_packet_size, ack_eliciting, seq_num);
+ return (this->_qc->direction() == NET_VCONNECTION_IN && !this->_is_handshake_done_sent) ||
+ this->_crypto_streams[static_cast<int>(level)].will_generate_frame(level, current_packet_size, ack_eliciting, seq_num);
}
QUICFrame *
@@ -338,8 +356,23 @@ QUICHandshake::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t
QUICFrame *frame = nullptr;
if (this->_is_level_matched(level)) {
+ // CRYPTO
frame = this->_crypto_streams[static_cast<int>(level)].generate_frame(buf, level, connection_credit, maximum_frame_size,
current_packet_size, seq_num);
+ if (frame) {
+ return frame;
+ }
+ }
+
+ if (level == QUICEncryptionLevel::ONE_RTT) {
+ // HANDSHAKE_DONE
+ if (!this->_is_handshake_done_sent && this->is_completed()) {
+ frame = QUICFrameFactory::create_handshake_done_frame(buf, this->_issue_frame_id(), this);
+ }
+ if (frame) {
+ this->_is_handshake_done_sent = true;
+ return frame;
+ }
}
return frame;
@@ -351,7 +384,7 @@ QUICHandshake::_load_local_server_transport_parameters(const QUICTPConfig &tp_co
QUICTransportParametersInEncryptedExtensions *tp = new QUICTransportParametersInEncryptedExtensions();
// MUSTs
- tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast<uint16_t>(tp_config.no_activity_timeout()));
+ 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(),
this->_qc->first_connection_id().length());
@@ -376,6 +409,9 @@ QUICHandshake::_load_local_server_transport_parameters(const QUICTPConfig &tp_co
if (tp_config.initial_max_stream_data_uni() != 0) {
tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI, tp_config.initial_max_stream_data_uni());
}
+ if (tp_config.disable_active_migration()) {
+ tp->set(QUICTransportParameterId::DISABLE_ACTIVE_MIGRATION, nullptr, 0);
+ }
if (pref_addr != nullptr) {
uint8_t pref_addr_buf[QUICPreferredAddress::MAX_LEN];
uint16_t len;
@@ -392,6 +428,11 @@ QUICHandshake::_load_local_server_transport_parameters(const QUICTPConfig &tp_co
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);
+ }
+
this->_local_transport_parameters = std::shared_ptr<QUICTransportParameters>(tp);
this->_hs_protocol->set_local_transport_parameters(this->_local_transport_parameters);
}
@@ -402,7 +443,7 @@ QUICHandshake::_load_local_client_transport_parameters(const QUICTPConfig &tp_co
QUICTransportParametersInClientHello *tp = new QUICTransportParametersInClientHello();
// MUSTs
- tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast<uint16_t>(tp_config.no_activity_timeout()));
+ tp->set(QUICTransportParameterId::MAX_IDLE_TIMEOUT, static_cast<uint16_t>(tp_config.no_activity_timeout()));
// MAYs
if (tp_config.initial_max_data() != 0) {
@@ -428,6 +469,11 @@ QUICHandshake::_load_local_client_transport_parameters(const QUICTPConfig &tp_co
tp->set(QUICTransportParameterId::ACTIVE_CONNECTION_ID_LIMIT, tp_config.active_cid_limit());
}
+ // Additional parameters
+ for (auto &¶m : tp_config.additional_tp()) {
+ tp->set(param.first, param.second.first, param.second.second);
+ }
+
this->_local_transport_parameters = std::shared_ptr<QUICTransportParameters>(tp);
this->_hs_protocol->set_local_transport_parameters(std::unique_ptr<QUICTransportParameters>(tp));
}
@@ -452,18 +498,13 @@ QUICHandshake::do_handshake()
// TODO: check size
if (bytes_avail > 0) {
stream->read(in.buf + in.offsets[index], bytes_avail);
- in.offsets[index] = bytes_avail;
- in.offsets[4] += bytes_avail;
}
+ in.offsets[index + 1] = in.offsets[index] + bytes_avail;
}
}
- QUICHandshakeMsgs out;
- uint8_t out_buf[MAX_HANDSHAKE_MSG_LEN] = {0};
- out.buf = out_buf;
- out.max_buf_len = MAX_HANDSHAKE_MSG_LEN;
-
- int result = this->_hs_protocol->handshake(&out, &in);
+ QUICHandshakeMsgs *out = nullptr;
+ int result = this->_hs_protocol->handshake(&out, &in);
if (this->_remote_transport_parameters == nullptr) {
if (!this->check_remote_transport_parameters()) {
result = 0;
@@ -471,18 +512,25 @@ QUICHandshake::do_handshake()
}
if (result == 1) {
- for (auto level : QUIC_ENCRYPTION_LEVELS) {
- int index = static_cast<int>(level);
- QUICCryptoStream *stream = &this->_crypto_streams[index];
- size_t len = out.offsets[index + 1] - out.offsets[index];
- // TODO: check size
- if (len > 0) {
- stream->write(out.buf + out.offsets[index], len);
+ if (out) {
+ for (auto level : QUIC_ENCRYPTION_LEVELS) {
+ int index = static_cast<int>(level);
+ QUICCryptoStream *stream = &this->_crypto_streams[index];
+ size_t len = out->offsets[index + 1] - out->offsets[index];
+ // TODO: check size
+ if (len > 0) {
+ stream->write(out->buf + out->offsets[index], len);
+ }
}
}
- } else if (out.error_code != 0) {
+ } else {
this->_hs_protocol->abort_handshake();
- error = std::make_unique<QUICConnectionError>(QUICErrorClass::TRANSPORT, out.error_code);
+ if (this->_hs_protocol->has_crypto_error()) {
+ error = std::make_unique<QUICConnectionError>(QUICErrorClass::TRANSPORT, this->_hs_protocol->crypto_error());
+ } else {
+ error = std::make_unique<QUICConnectionError>(QUICErrorClass::TRANSPORT,
+ static_cast<uint16_t>(QUICTransErrorCode::PROTOCOL_VIOLATION));
+ }
}
return error;
@@ -495,7 +543,7 @@ QUICHandshake::_abort_handshake(QUICTransErrorCode code)
this->_hs_protocol->abort_handshake();
- this->_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(code)));
+ this->_qc->close_quic_connection(QUICConnectionErrorUPtr(new QUICConnectionError(code)));
}
/*
@@ -514,3 +562,10 @@ QUICHandshake::_is_level_matched(QUICEncryptionLevel level)
{
return true;
}
+
+void
+QUICHandshake::_on_frame_lost(QUICFrameInformationUPtr &info)
+{
+ ink_assert(info->type == QUICFrameType::HANDSHAKE_DONE);
+ this->_is_handshake_done_sent = false;
+}
diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h
index 49ef437..5af42d8 100644
--- a/iocore/net/quic/QUICHandshake.h
+++ b/iocore/net/quic/QUICHandshake.h
@@ -35,6 +35,7 @@
*/
class QUICVersionNegotiator;
class QUICPacketFactory;
+class QUICHandshakeProtocol;
class SSLNextProtocolSet;
class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator
@@ -57,12 +58,12 @@ public:
// for client side
QUICConnectionErrorUPtr start(const QUICTPConfig &tp_config, QUICPacketFactory *packet_factory, bool vn_exercise_enabled);
- QUICConnectionErrorUPtr negotiate_version(const QUICPacket &packet, QUICPacketFactory *packet_factory);
+ QUICConnectionErrorUPtr negotiate_version(const QUICVersionNegotiationPacketR &packet, QUICPacketFactory *packet_factory);
void reset();
// for server side
- QUICConnectionErrorUPtr start(const QUICTPConfig &tp_config, const QUICPacket &initial_packet, QUICPacketFactory *packet_factory,
- const QUICPreferredAddress *pref_addr);
+ QUICConnectionErrorUPtr start(const QUICTPConfig &tp_config, const QUICInitialPacketR &initial_packet,
+ QUICPacketFactory *packet_factory, const QUICPreferredAddress *pref_addr);
QUICConnectionErrorUPtr do_handshake();
@@ -77,6 +78,7 @@ public:
bool is_version_negotiated() const;
bool is_completed() const;
+ bool is_confirmed() const;
bool is_stateless_retry_enabled() const;
bool has_remote_tp() const;
@@ -102,4 +104,10 @@ private:
std::shared_ptr<const QUICTransportParameters> _remote_transport_parameters = nullptr;
void _abort_handshake(QUICTransErrorCode code);
+
+ bool _is_handshake_done_sent = false;
+ bool _is_handshake_done_received = false;
+
+ // QUICFrameGenerator
+ void _on_frame_lost(QUICFrameInformationUPtr &info) override;
};
diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h
index fd4c68b..2d56e02 100644
--- a/iocore/net/quic/QUICHandshakeProtocol.h
+++ b/iocore/net/quic/QUICHandshakeProtocol.h
@@ -43,7 +43,7 @@ public:
QUICHandshakeProtocol(QUICPacketProtectionKeyInfo &pp_key_info) : _pp_key_info(pp_key_info) {}
virtual ~QUICHandshakeProtocol(){};
- virtual int handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) = 0;
+ virtual int handshake(QUICHandshakeMsgs **out, const QUICHandshakeMsgs *in) = 0;
virtual void reset() = 0;
virtual bool is_handshake_finished() const = 0;
virtual bool is_ready_to_derive() const = 0;
@@ -58,6 +58,8 @@ public:
virtual QUICEncryptionLevel current_encryption_level() const = 0;
virtual void abort_handshake() = 0;
+ virtual bool has_crypto_error() const = 0;
+ virtual uint64_t crypto_error() const = 0;
protected:
QUICPacketProtectionKeyInfo &_pp_key_info;
diff --git a/iocore/net/quic/QUICIntUtil.cc b/iocore/net/quic/QUICIntUtil.cc
index e9840ca..26159d7 100644
--- a/iocore/net/quic/QUICIntUtil.cc
+++ b/iocore/net/quic/QUICIntUtil.cc
@@ -102,11 +102,11 @@ QUICVariableInt::decode(uint64_t &dst, size_t &len, const uint8_t *src, size_t s
}
uint64_t
-QUICIntUtil::read_QUICVariableInt(const uint8_t *buf)
+QUICIntUtil::read_QUICVariableInt(const uint8_t *buf, size_t buf_len)
{
uint64_t dst = 0;
size_t len = 0;
- QUICVariableInt::decode(dst, len, buf, 8);
+ QUICVariableInt::decode(dst, len, buf, buf_len);
return dst;
}
diff --git a/iocore/net/quic/QUICIntUtil.h b/iocore/net/quic/QUICIntUtil.h
index c259bca..5116304 100644
--- a/iocore/net/quic/QUICIntUtil.h
+++ b/iocore/net/quic/QUICIntUtil.h
@@ -38,7 +38,7 @@ public:
class QUICIntUtil
{
public:
- static uint64_t read_QUICVariableInt(const uint8_t *buf);
+ static uint64_t read_QUICVariableInt(const uint8_t *buf, size_t buf_len);
static void write_QUICVariableInt(uint64_t data, uint8_t *buf, size_t *len);
static uint64_t read_nbytes_as_uint(const uint8_t *buf, uint8_t n);
static void write_uint_as_nbytes(uint64_t value, uint8_t n, uint8_t *buf, size_t *len);
diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc
index 98d091d..24c2b84 100644
--- a/iocore/net/quic/QUICKeyGenerator.cc
+++ b/iocore/net/quic/QUICKeyGenerator.cc
@@ -45,8 +45,8 @@ 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)
{
- const QUIC_EVP_CIPHER *cipher = this->_get_cipher_for_initial();
- const EVP_MD *md = EVP_sha256();
+ const EVP_CIPHER *cipher = this->_get_cipher_for_initial();
+ const EVP_MD *md = EVP_sha256();
uint8_t secret[512];
size_t secret_len = sizeof(secret);
QUICHKDF hkdf(md);
@@ -79,14 +79,14 @@ QUICKeyGenerator::generate(uint8_t *hp_key, uint8_t *pp_key, uint8_t *iv, size_t
void
QUICKeyGenerator::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 QUIC_EVP_CIPHER *cipher, QUICHKDF &hkdf)
+ size_t secret_len, const EVP_CIPHER *cipher, QUICHKDF &hkdf)
{
this->_generate(hp_key, pp_key, iv, iv_len, hkdf, secret, secret_len, cipher);
}
int
QUICKeyGenerator::_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 QUIC_EVP_CIPHER *cipher)
+ size_t secret_len, const EVP_CIPHER *cipher)
{
// Generate key, iv, and hp_key
// key = HKDF-Expand-Label(S, "quic key", "", key_length)
diff --git a/iocore/net/quic/QUICKeyGenerator.h b/iocore/net/quic/QUICKeyGenerator.h
index a82ad43..c2ff89f 100644
--- a/iocore/net/quic/QUICKeyGenerator.h
+++ b/iocore/net/quic/QUICKeyGenerator.h
@@ -46,7 +46,7 @@ public:
void generate(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 QUIC_EVP_CIPHER *cipher, QUICHKDF &hkdf);
+ const EVP_CIPHER *cipher, QUICHKDF &hkdf);
private:
Context _ctx = Context::SERVER;
@@ -55,15 +55,15 @@ private:
size_t _last_secret_len = 0;
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 QUIC_EVP_CIPHER *cipher);
+ 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_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;
int _generate_hp(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t hp_length) const;
- size_t _get_key_len(const QUIC_EVP_CIPHER *cipher) const;
- size_t _get_iv_len(const QUIC_EVP_CIPHER *cipher) const;
- const QUIC_EVP_CIPHER *_get_cipher_for_initial() const;
- const QUIC_EVP_CIPHER *_get_cipher_for_protected_packet(const SSL *ssl) const;
+ size_t _get_key_len(const EVP_CIPHER *cipher) const;
+ size_t _get_iv_len(const EVP_CIPHER *cipher) const;
+ const EVP_CIPHER *_get_cipher_for_initial() const;
+ const EVP_CIPHER *_get_cipher_for_protected_packet(const SSL *ssl) const;
};
diff --git a/iocore/net/quic/QUICKeyGenerator_boringssl.cc b/iocore/net/quic/QUICKeyGenerator_boringssl.cc
index e2204bb..4406bbd 100644
--- a/iocore/net/quic/QUICKeyGenerator_boringssl.cc
+++ b/iocore/net/quic/QUICKeyGenerator_boringssl.cc
@@ -25,33 +25,34 @@
#include <openssl/ssl.h>
size_t
-QUICKeyGenerator::_get_key_len(const QUIC_EVP_CIPHER *cipher) const
+QUICKeyGenerator::_get_key_len(const EVP_CIPHER *cipher) const
{
- return EVP_AEAD_key_length(cipher);
+ return EVP_CIPHER_key_length(cipher);
}
size_t
-QUICKeyGenerator::_get_iv_len(const QUIC_EVP_CIPHER *cipher) const
+QUICKeyGenerator::_get_iv_len(const EVP_CIPHER *cipher) const
{
- return EVP_AEAD_nonce_length(cipher);
+ return EVP_CIPHER_iv_length(cipher);
}
-const QUIC_EVP_CIPHER *
+const EVP_CIPHER *
QUICKeyGenerator::_get_cipher_for_initial() const
{
- return EVP_aead_aes_128_gcm();
+ return EVP_aes_128_gcm();
}
-const QUIC_EVP_CIPHER *
+const EVP_CIPHER *
QUICKeyGenerator::_get_cipher_for_protected_packet(const SSL *ssl) const
{
switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) {
case TLS1_CK_AES_128_GCM_SHA256:
- return EVP_aead_aes_128_gcm();
+ return EVP_aes_128_gcm();
case TLS1_CK_AES_256_GCM_SHA384:
- return EVP_aead_aes_256_gcm();
+ return EVP_aes_256_gcm();
case TLS1_CK_CHACHA20_POLY1305_SHA256:
- return EVP_aead_chacha20_poly1305();
+ return nullptr;
+ // return EVP_aead_chacha20_poly1305();
default:
ink_assert(false);
return nullptr;
diff --git a/iocore/net/quic/QUICKeyGenerator_openssl.cc b/iocore/net/quic/QUICKeyGenerator_legacy.cc
similarity index 90%
copy from iocore/net/quic/QUICKeyGenerator_openssl.cc
copy to iocore/net/quic/QUICKeyGenerator_legacy.cc
index 5d9d029..03b46e1 100644
--- a/iocore/net/quic/QUICKeyGenerator_openssl.cc
+++ b/iocore/net/quic/QUICKeyGenerator_legacy.cc
@@ -26,24 +26,24 @@
#include <openssl/ssl.h>
size_t
-QUICKeyGenerator::_get_key_len(const QUIC_EVP_CIPHER *cipher) const
+QUICKeyGenerator::_get_key_len(const EVP_CIPHER *cipher) const
{
return EVP_CIPHER_key_length(cipher);
}
size_t
-QUICKeyGenerator::_get_iv_len(const QUIC_EVP_CIPHER *cipher) const
+QUICKeyGenerator::_get_iv_len(const EVP_CIPHER *cipher) const
{
return EVP_CIPHER_iv_length(cipher);
}
-const QUIC_EVP_CIPHER *
+const EVP_CIPHER *
QUICKeyGenerator::_get_cipher_for_initial() const
{
return EVP_aes_128_gcm();
}
-const QUIC_EVP_CIPHER *
+const EVP_CIPHER *
QUICKeyGenerator::_get_cipher_for_protected_packet(const SSL *ssl) const
{
switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) {
diff --git a/iocore/net/quic/QUICKeyGenerator_openssl.cc b/iocore/net/quic/QUICKeyGenerator_openssl.cc
index 5d9d029..e7bb227 100644
--- a/iocore/net/quic/QUICKeyGenerator_openssl.cc
+++ b/iocore/net/quic/QUICKeyGenerator_openssl.cc
@@ -24,26 +24,25 @@
#include "QUICKeyGenerator.h"
#include <openssl/ssl.h>
-
size_t
-QUICKeyGenerator::_get_key_len(const QUIC_EVP_CIPHER *cipher) const
+QUICKeyGenerator::_get_key_len(const EVP_CIPHER *cipher) const
{
return EVP_CIPHER_key_length(cipher);
}
size_t
-QUICKeyGenerator::_get_iv_len(const QUIC_EVP_CIPHER *cipher) const
+QUICKeyGenerator::_get_iv_len(const EVP_CIPHER *cipher) const
{
return EVP_CIPHER_iv_length(cipher);
}
-const QUIC_EVP_CIPHER *
+const EVP_CIPHER *
QUICKeyGenerator::_get_cipher_for_initial() const
{
return EVP_aes_128_gcm();
}
-const QUIC_EVP_CIPHER *
+const EVP_CIPHER *
QUICKeyGenerator::_get_cipher_for_protected_packet(const SSL *ssl) const
{
switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) {
@@ -61,3 +60,21 @@ QUICKeyGenerator::_get_cipher_for_protected_packet(const SSL *ssl) const
return nullptr;
}
}
+
+// SSL_HANDSHAKE_MAC_SHA256, SSL_HANDSHAKE_MAC_SHA384 are defind in `ssl/internal.h` of BoringSSL
+/*
+const EVP_MD *
+QUICKeyGenerator::get_handshake_digest(const SSL *ssl)
+{
+ switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) {
+ case TLS1_CK_AES_128_GCM_SHA256:
+ case TLS1_CK_CHACHA20_POLY1305_SHA256:
+ return EVP_sha256();
+ case TLS1_CK_AES_256_GCM_SHA384:
+ return EVP_sha384();
+ default:
+ ink_assert(false);
+ return nullptr;
+ }
+}
+*/
diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc
index 4d6397b..6a0138d 100644
--- a/iocore/net/quic/QUICLossDetector.cc
+++ b/iocore/net/quic/QUICLossDetector.cc
@@ -38,7 +38,7 @@
#define QUICLDVDebug(fmt, ...) \
Debug("v_quic_loss_detector", "[%s] " fmt, this->_context.connection_info()->cids().data(), ##__VA_ARGS__)
-QUICLossDetector::QUICLossDetector(QUICLDContext &context, QUICCongestionController *cc, QUICRTTMeasure *rtt_measure,
+QUICLossDetector::QUICLossDetector(QUICContext &context, QUICCongestionController *cc, QUICRTTMeasure *rtt_measure,
QUICPinger *pinger, QUICPadder *padder)
: _rtt_measure(rtt_measure), _pinger(pinger), _padder(padder), _cc(cc), _context(context)
{
@@ -444,6 +444,7 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumberSpace pn_space)
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.
@@ -487,7 +488,7 @@ QUICLossDetector::_send_packet(QUICEncryptionLevel level, bool padded)
if (padded) {
this->_padder->request(level);
} else {
- this->_pinger->request();
+ this->_pinger->request(level);
}
this->_cc->add_extra_credit();
}
@@ -497,23 +498,25 @@ QUICLossDetector::_send_one_or_two_packet()
{
this->_send_packet(QUICEncryptionLevel::ONE_RTT);
this->_send_packet(QUICEncryptionLevel::ONE_RTT);
- ink_assert(this->_pinger->count() >= 2);
+ ink_assert(this->_pinger->count(QUICEncryptionLevel::ONE_RTT) >= 2);
QUICLDDebug("[%s] send ping frame %" PRIu64, QUICDebugNames::encryption_level(QUICEncryptionLevel::ONE_RTT),
- this->_pinger->count());
+ this->_pinger->count(QUICEncryptionLevel::ONE_RTT));
}
void
QUICLossDetector::_send_one_handshake_packets()
{
this->_send_packet(QUICEncryptionLevel::HANDSHAKE);
- QUICLDDebug("[%s] send handshake packet", QUICDebugNames::encryption_level(QUICEncryptionLevel::HANDSHAKE));
+ QUICLDDebug("[%s] send handshake packet: ping count=%" PRIu64, QUICDebugNames::encryption_level(QUICEncryptionLevel::HANDSHAKE),
+ this->_pinger->count(QUICEncryptionLevel::HANDSHAKE));
}
void
QUICLossDetector::_send_one_padded_packets()
{
this->_send_packet(QUICEncryptionLevel::INITIAL, true);
- QUICLDDebug("[%s] send PADDING frame", QUICDebugNames::encryption_level(QUICEncryptionLevel::INITIAL));
+ QUICLDDebug("[%s] send PADDING frame: ping count=%" PRIu64, QUICDebugNames::encryption_level(QUICEncryptionLevel::INITIAL),
+ this->_pinger->count(QUICEncryptionLevel::INITIAL));
}
// ===== Functions below are helper functions =====
diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h
index 5e4005b..42afd81 100644
--- a/iocore/net/quic/QUICLossDetector.h
+++ b/iocore/net/quic/QUICLossDetector.h
@@ -59,7 +59,7 @@ public:
class QUICNewRenoCongestionController : public QUICCongestionController
{
public:
- QUICNewRenoCongestionController(QUICCCContext &context);
+ QUICNewRenoCongestionController(QUICContext &context);
virtual ~QUICNewRenoCongestionController() {}
void on_packet_sent(size_t bytes_sent) override;
void on_packet_acked(const QUICPacketInfo &acked_packet) override;
@@ -71,9 +71,9 @@ public:
bool is_app_limited();
// Debug
- uint32_t bytes_in_flight() const;
- uint32_t congestion_window() const;
- uint32_t current_ssthresh() const;
+ uint32_t bytes_in_flight() const override;
+ uint32_t congestion_window() const override;
+ uint32_t current_ssthresh() const override;
void add_extra_credit() override;
@@ -105,13 +105,13 @@ private:
bool _in_congestion_recovery(ink_hrtime sent_time);
- QUICCCContext &_context;
+ QUICContext &_context;
};
class QUICLossDetector : public Continuation, public QUICFrameHandler
{
public:
- QUICLossDetector(QUICLDContext &context, QUICCongestionController *cc, QUICRTTMeasure *rtt_measure, QUICPinger *pinger,
+ QUICLossDetector(QUICContext &context, QUICCongestionController *cc, QUICRTTMeasure *rtt_measure, QUICPinger *pinger,
QUICPadder *padder);
~QUICLossDetector();
@@ -185,7 +185,7 @@ private:
QUICPadder *_padder = nullptr;
QUICCongestionController *_cc = nullptr;
- QUICLDContext &_context;
+ QUICContext &_context;
};
class QUICRTTMeasure : public QUICRTTProvider
diff --git a/iocore/net/quic/QUICNewRenoCongestionController.cc b/iocore/net/quic/QUICNewRenoCongestionController.cc
index 080c910..db6ec90 100644
--- a/iocore/net/quic/QUICNewRenoCongestionController.cc
+++ b/iocore/net/quic/QUICNewRenoCongestionController.cc
@@ -38,7 +38,7 @@
this->_context.connection_info()->cids().data(), this->_congestion_window, this->_bytes_in_flight, this->_ssthresh, \
this->_extra_packets_count, ##__VA_ARGS__)
-QUICNewRenoCongestionController::QUICNewRenoCongestionController(QUICCCContext &context)
+QUICNewRenoCongestionController::QUICNewRenoCongestionController(QUICContext &context)
: _cc_mutex(new_ProxyMutex()), _context(context)
{
auto &cc_config = context.cc_config();
@@ -94,10 +94,13 @@ QUICNewRenoCongestionController::on_packet_acked(const QUICPacketInfo &acked_pac
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 chaged");
} 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");
}
@@ -116,6 +119,9 @@ QUICNewRenoCongestionController::_congestion_event(ink_hrtime sent_time)
this->_congestion_window *= this->_k_loss_reduction_factor;
this->_congestion_window = std::max(this->_congestion_window, this->_k_minimum_window);
this->_ssthresh = this->_congestion_window;
+ 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);
}
}
diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc
index 534ed27..494dd32 100644
--- a/iocore/net/quic/QUICPacket.cc
+++ b/iocore/net/quic/QUICPacket.cc
@@ -23,258 +23,438 @@
#include "QUICPacket.h"
+#include <algorithm>
+
#include <tscore/ink_assert.h>
#include <tscore/Diags.h>
#include "QUICIntUtil.h"
#include "QUICDebugNames.h"
+#include "QUICRetryIntegrityTag.h"
using namespace std::literals;
-static constexpr std::string_view tag = "quic_packet"sv;
-static constexpr uint64_t aead_tag_len = 16;
+static constexpr uint64_t aead_tag_len = 16;
+static constexpr int LONG_HDR_OFFSET_CONNECTION_ID = 6;
+static constexpr int LONG_HDR_OFFSET_VERSION = 1;
#define QUICDebug(dcid, scid, fmt, ...) \
Debug(tag.data(), "[%08" PRIx32 "-%08" PRIx32 "] " fmt, dcid.h32(), scid.h32(), ##__VA_ARGS__);
-ClassAllocator<QUICPacket> quicPacketAllocator("quicPacketAllocator");
-ClassAllocator<QUICPacketLongHeader> quicPacketLongHeaderAllocator("quicPacketLongHeaderAllocator");
-ClassAllocator<QUICPacketShortHeader> quicPacketShortHeaderAllocator("quicPacketShortHeaderAllocator");
-
-static constexpr int LONG_HDR_OFFSET_CONNECTION_ID = 6;
-static constexpr int LONG_HDR_OFFSET_VERSION = 1;
-
//
-// QUICPacketHeader
+// QUICPacket
//
-const uint8_t *
-QUICPacketHeader::buf()
-{
- if (this->_buf) {
- return this->_buf.get();
- } else {
- // TODO Reuse serialzied data if nothing has changed
- this->store(this->_serialized, &this->_buf_len);
- if (this->_buf_len > MAX_PACKET_HEADER_LEN) {
- ink_assert(!"Serialized packet header is too long");
- }
+QUICPacket::QUICPacket() {}
- this->_buf_len += this->_payload_length;
- return this->_serialized;
- }
-}
+QUICPacket::QUICPacket(bool ack_eliciting, bool probing) : _is_ack_eliciting(ack_eliciting), _is_probing_packet(probing) {}
-const IpEndpoint &
-QUICPacketHeader::from() const
+QUICPacket::~QUICPacket() {}
+
+QUICKeyPhase
+QUICPacket::key_phase() const
{
- return this->_from;
+ ink_assert(!"This function should not be called");
+ return QUICKeyPhase::INITIAL;
}
-const IpEndpoint &
-QUICPacketHeader::to() const
+bool
+QUICPacket::is_ack_eliciting() const
{
- return this->_to;
+ return this->_is_ack_eliciting;
}
bool
-QUICPacketHeader::is_crypto_packet() const
+QUICPacket::is_probing_packet() const
{
- return false;
+ return this->_is_probing_packet;
}
uint16_t
-QUICPacketHeader::packet_size() const
+QUICPacket::header_size() const
{
- return this->_buf_len;
-}
+ uint16_t size = 0;
-QUICPacketHeaderUPtr
-QUICPacketHeader::load(const IpEndpoint from, const IpEndpoint to, ats_unique_buf buf, size_t len, QUICPacketNumber base)
-{
- QUICPacketHeaderUPtr header = QUICPacketHeaderUPtr(nullptr, &QUICPacketHeaderDeleter::delete_null_header);
- if (QUICInvariants::is_long_header(buf.get())) {
- QUICPacketLongHeader *long_header = quicPacketLongHeaderAllocator.alloc();
- new (long_header) QUICPacketLongHeader(from, to, std::move(buf), len, base);
- header = QUICPacketHeaderUPtr(long_header, &QUICPacketHeaderDeleter::delete_long_header);
- } else {
- QUICPacketShortHeader *short_header = quicPacketShortHeaderAllocator.alloc();
- new (short_header) QUICPacketShortHeader(from, to, std::move(buf), len, base);
- header = QUICPacketHeaderUPtr(short_header, &QUICPacketHeaderDeleter::delete_short_header);
+ for (auto b = this->header_block(); b; b = b->next) {
+ size += b->size();
}
- return header;
+
+ return size;
}
-QUICPacketHeaderUPtr
-QUICPacketHeader::build(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId destination_cid, QUICConnectionId source_cid,
- QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, bool crypto,
- ats_unique_buf payload, size_t len)
+uint16_t
+QUICPacket::payload_length() const
{
- QUICPacketLongHeader *long_header = quicPacketLongHeaderAllocator.alloc();
- new (long_header) QUICPacketLongHeader(type, key_phase, destination_cid, source_cid, packet_number, base_packet_number, version,
- crypto, std::move(payload), len);
- return QUICPacketHeaderUPtr(long_header, &QUICPacketHeaderDeleter::delete_long_header);
+ uint16_t size = 0;
+
+ for (auto b = this->payload_block(); b; b = b->next) {
+ size += b->size();
+ }
+
+ return size;
}
-QUICPacketHeaderUPtr
-QUICPacketHeader::build(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId destination_cid, QUICConnectionId source_cid,
- QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, bool crypto,
- ats_unique_buf payload, size_t len, ats_unique_buf token, size_t token_len)
+uint16_t
+QUICPacket::size() const
{
- QUICPacketLongHeader *long_header = quicPacketLongHeaderAllocator.alloc();
- new (long_header) QUICPacketLongHeader(type, key_phase, destination_cid, source_cid, packet_number, base_packet_number, version,
- crypto, std::move(payload), len, std::move(token), token_len);
- return QUICPacketHeaderUPtr(long_header, &QUICPacketHeaderDeleter::delete_long_header);
+ return this->header_size() + this->payload_length();
}
-QUICPacketHeaderUPtr
-QUICPacketHeader::build(QUICPacketType type, QUICKeyPhase key_phase, QUICVersion version, QUICConnectionId destination_cid,
- QUICConnectionId source_cid, QUICConnectionId original_dcid, ats_unique_buf retry_token,
- size_t retry_token_len)
+void
+QUICPacket::store(uint8_t *buf, size_t *len) const
{
- QUICPacketLongHeader *long_header = quicPacketLongHeaderAllocator.alloc();
- new (long_header) QUICPacketLongHeader(type, key_phase, version, destination_cid, source_cid, original_dcid,
- std::move(retry_token), retry_token_len);
- return QUICPacketHeaderUPtr(long_header, &QUICPacketHeaderDeleter::delete_long_header);
+ size_t written = 0;
+ Ptr<IOBufferBlock> block;
+
+ block = this->header_block();
+ while (block) {
+ memcpy(buf + written, block->start(), block->size());
+ written += block->size();
+ block = block->next;
+ }
+
+ block = this->payload_block();
+ while (block) {
+ memcpy(buf + written, block->start(), block->size());
+ written += block->size();
+ block = block->next;
+ }
+
+ *len = written;
}
-QUICPacketHeaderUPtr
-QUICPacketHeader::build(QUICPacketType type, QUICKeyPhase key_phase, QUICPacketNumber packet_number,
- QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len)
+uint8_t
+QUICPacket::calc_packet_number_len(QUICPacketNumber num, QUICPacketNumber base)
{
- QUICPacketShortHeader *short_header = quicPacketShortHeaderAllocator.alloc();
- new (short_header) QUICPacketShortHeader(type, key_phase, packet_number, base_packet_number, std::move(payload), len);
- return QUICPacketHeaderUPtr(short_header, &QUICPacketHeaderDeleter::delete_short_header);
+ uint64_t d = (num - base) * 2;
+ uint8_t len = 0;
+
+ if (d > 0xFFFFFF) {
+ len = 4;
+ } else if (d > 0xFFFF) {
+ len = 3;
+ } else if (d > 0xFF) {
+ len = 2;
+ } else {
+ len = 1;
+ }
+
+ return len;
}
-QUICPacketHeaderUPtr
-QUICPacketHeader::build(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId connection_id, QUICPacketNumber packet_number,
- QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len)
+bool
+QUICPacket::encode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len)
{
- QUICPacketShortHeader *short_header = quicPacketShortHeaderAllocator.alloc();
- new (short_header)
- QUICPacketShortHeader(type, key_phase, connection_id, packet_number, base_packet_number, std::move(payload), len);
- return QUICPacketHeaderUPtr(short_header, &QUICPacketHeaderDeleter::delete_short_header);
+ uint64_t mask = 0;
+ switch (len) {
+ case 1:
+ mask = 0xFF;
+ break;
+ case 2:
+ mask = 0xFFFF;
+ break;
+ case 3:
+ mask = 0xFFFFFF;
+ break;
+ case 4:
+ mask = 0xFFFFFFFF;
+ break;
+ default:
+ ink_assert(!"len must be 1, 2, or 4");
+ return false;
+ }
+ dst = src & mask;
+
+ return true;
}
-QUICPacketHeaderUPtr
-QUICPacketHeader::clone() const
+bool
+QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len, QUICPacketNumber largest_acked)
{
- return QUICPacketHeaderUPtr(nullptr, &QUICPacketHeaderDeleter::delete_null_header);
+ ink_assert(len == 1 || len == 2 || len == 3 || len == 4);
+
+ uint64_t maximum_diff = 0;
+ switch (len) {
+ case 1:
+ maximum_diff = 0x100;
+ break;
+ case 2:
+ maximum_diff = 0x10000;
+ break;
+ case 3:
+ maximum_diff = 0x1000000;
+ break;
+ case 4:
+ maximum_diff = 0x100000000;
+ break;
+ default:
+ ink_assert(!"len must be 1, 2, 3 or 4");
+ }
+ QUICPacketNumber base = largest_acked & (~(maximum_diff - 1));
+ QUICPacketNumber candidate1 = base + src;
+ QUICPacketNumber candidate2 = base + src + maximum_diff;
+ QUICPacketNumber expected = largest_acked + 1;
+
+ if (((candidate1 > expected) ? (candidate1 - expected) : (expected - candidate1)) <
+ ((candidate2 > expected) ? (candidate2 - expected) : (expected - candidate2))) {
+ dst = candidate1;
+ } else {
+ dst = candidate2;
+ }
+
+ return true;
}
//
-// QUICPacketLongHeader
+// QUICPacketR
//
-QUICPacketLongHeader::QUICPacketLongHeader(const IpEndpoint from, const IpEndpoint to, ats_unique_buf buf, size_t len,
- QUICPacketNumber base)
- : QUICPacketHeader(from, to, std::move(buf), len, base)
+QUICPacketR::QUICPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to) : _udp_con(udp_con), _from(from), _to(to) {}
+
+UDPConnection *
+QUICPacketR::udp_con() const
{
- this->_key_phase = QUICTypeUtil::key_phase(this->type());
- uint8_t *raw_buf = this->_buf.get();
+ return this->_udp_con;
+}
- uint8_t dcil = 0;
- uint8_t scil = 0;
- QUICPacketLongHeader::dcil(dcil, raw_buf, len);
- QUICPacketLongHeader::scil(scil, raw_buf, len);
+const IpEndpoint &
+QUICPacketR::from() const
+{
+ return this->_from;
+}
- size_t offset = LONG_HDR_OFFSET_CONNECTION_ID;
- this->_destination_cid = {raw_buf + offset, dcil};
- offset += dcil + 1;
- this->_source_cid = {raw_buf + offset, scil};
- offset += scil;
+const IpEndpoint &
+QUICPacketR::to() const
+{
+ return this->_to;
+}
- if (this->type() != QUICPacketType::VERSION_NEGOTIATION) {
- if (this->type() == QUICPacketType::RETRY) {
- uint8_t odcil = raw_buf[offset];
- offset += 1;
+bool
+QUICPacketR::type(QUICPacketType &type, const uint8_t *packet, size_t packet_len)
+{
+ if (packet_len < 1) {
+ return false;
+ }
- this->_original_dcid = {raw_buf + offset, odcil};
- offset += odcil;
- } else {
- if (this->type() == QUICPacketType::INITIAL) {
- // Token Length Field
- this->_token_len = QUICIntUtil::read_QUICVariableInt(raw_buf + offset);
- offset += QUICVariableInt::size(raw_buf + offset);
- // Token Field
- this->_token_offset = offset;
- offset += this->_token_len;
- }
+ if (QUICInvariants::is_long_header(packet)) {
+ return QUICLongHeaderPacketR::type(type, packet, packet_len);
+ } else {
+ type = QUICPacketType::PROTECTED;
+ return true;
+ }
+}
+
+bool
+QUICPacketR::read_essential_info(Ptr<IOBufferBlock> block, QUICPacketType &type, QUICVersion &version, QUICConnectionId &dcid,
+ QUICConnectionId &scid, QUICPacketNumber &packet_number, QUICPacketNumber base_packet_number,
+ QUICKeyPhase &key_phase)
+{
+ uint8_t tmp[47 + 64];
+ IOBufferReader reader;
+ reader.block = block;
+ int64_t len = std::min(static_cast<int64_t>(sizeof(tmp)), reader.read_avail());
- // Length Field
- offset += QUICVariableInt::size(raw_buf + offset);
+ if (len < 10) {
+ return false;
+ }
- // PN Field
- int pn_len = QUICTypeUtil::read_QUICPacketNumberLen(raw_buf);
- QUICPacket::decode_packet_number(this->_packet_number, QUICTypeUtil::read_QUICPacketNumber(raw_buf + offset, pn_len), pn_len,
- this->_base_packet_number);
- offset += pn_len;
+ reader.memcpy(tmp, 1, 0);
+ if (QUICInvariants::is_long_header(tmp)) {
+ reader.memcpy(tmp, len, 0);
+ type = static_cast<QUICPacketType>((0x30 & tmp[0]) >> 4);
+ QUICInvariants::version(version, tmp, len);
+ if (version == 0x00) {
+ type = QUICPacketType::VERSION_NEGOTIATION;
+ }
+ if (!QUICInvariants::dcid(dcid, tmp, len) || !QUICInvariants::scid(scid, tmp, len)) {
+ return false;
+ }
+ if (type != QUICPacketType::RETRY) {
+ int packet_number_len = QUICTypeUtil::read_QUICPacketNumberLen(tmp);
+ size_t length_offset = 7 + dcid.length() + scid.length();
+ if (length_offset >= static_cast<uint64_t>(len)) {
+ return false;
+ }
+ uint64_t value;
+ size_t field_len;
+ QUICVariableInt::decode(value, field_len, tmp + length_offset);
+ switch (type) {
+ case QUICPacketType::INITIAL:
+ length_offset += field_len + value;
+ if (length_offset >= static_cast<uint64_t>(len)) {
+ return false;
+ }
+ QUICVariableInt::decode(value, field_len, tmp + length_offset);
+ if (length_offset + field_len >= static_cast<uint64_t>(len)) {
+ return false;
+ }
+ if (length_offset + field_len + packet_number_len > static_cast<uint64_t>(len)) {
+ return false;
+ }
+ packet_number = QUICTypeUtil::read_QUICPacketNumber(tmp + length_offset + field_len, packet_number_len);
+ key_phase = QUICKeyPhase::INITIAL;
+ break;
+ case QUICPacketType::ZERO_RTT_PROTECTED:
+ if (length_offset + field_len + packet_number_len >= static_cast<uint64_t>(len)) {
+ return false;
+ }
+ packet_number = QUICTypeUtil::read_QUICPacketNumber(tmp + length_offset + field_len, packet_number_len);
+ key_phase = QUICKeyPhase::ZERO_RTT;
+ break;
+ case QUICPacketType::HANDSHAKE:
+ if (length_offset + field_len + packet_number_len >= static_cast<uint64_t>(len)) {
+ return false;
+ }
+ packet_number = QUICTypeUtil::read_QUICPacketNumber(tmp + length_offset + field_len, packet_number_len);
+ key_phase = QUICKeyPhase::INITIAL;
+ break;
+ case QUICPacketType::VERSION_NEGOTIATION:
+ break;
+ default:
+ break;
+ }
+ } else {
+ packet_number = 0;
+ }
+ } else {
+ len = std::min(static_cast<int64_t>(25), len);
+ reader.memcpy(tmp, len, 0);
+ type = QUICPacketType::PROTECTED;
+ QUICInvariants::dcid(dcid, tmp, len);
+ int packet_number_len = QUICTypeUtil::read_QUICPacketNumberLen(tmp);
+ if (tmp[0] & 0x04) {
+ key_phase = QUICKeyPhase::PHASE_1;
+ } else {
+ key_phase = QUICKeyPhase::PHASE_0;
}
+ packet_number = QUICTypeUtil::read_QUICPacketNumber(tmp + 1 + dcid.length(), packet_number_len);
}
+ return true;
+}
- this->_payload_offset = offset;
- this->_payload_length = len - this->_payload_offset;
+//
+// QUICLongHeaderPacket
+//
+QUICLongHeaderPacket::QUICLongHeaderPacket(QUICVersion version, QUICConnectionId dcid, QUICConnectionId scid, bool ack_eliciting,
+ bool probing, bool crypto)
+ : QUICPacket(ack_eliciting, probing), _version(version), _dcid(dcid), _scid(scid), _is_crypto_packet(crypto)
+{
}
-QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICKeyPhase key_phase, const QUICConnectionId &destination_cid,
- const QUICConnectionId &source_cid, QUICPacketNumber packet_number,
- QUICPacketNumber base_packet_number, QUICVersion version, bool crypto,
- ats_unique_buf buf, size_t len, ats_unique_buf token, size_t token_len)
- : QUICPacketHeader(type, packet_number, base_packet_number, true, version, std::move(buf), len, key_phase),
- _destination_cid(destination_cid),
- _source_cid(source_cid),
- _token_len(token_len),
- _token(std::move(token)),
- _is_crypto_packet(crypto)
+QUICConnectionId
+QUICLongHeaderPacket::destination_cid() const
{
- if (this->_type == QUICPacketType::VERSION_NEGOTIATION) {
- this->_buf_len =
- LONG_HDR_OFFSET_CONNECTION_ID + this->_destination_cid.length() + 1 + this->_source_cid.length() + this->_payload_length;
- } else {
- this->buf();
- }
+ return this->_dcid;
}
-QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICVersion version,
- const QUICConnectionId &destination_cid, const QUICConnectionId &source_cid,
- const QUICConnectionId &original_dcid, ats_unique_buf retry_token,
- size_t retry_token_len)
- : QUICPacketHeader(type, 0, 0, true, version, std::move(retry_token), retry_token_len, key_phase),
- _destination_cid(destination_cid),
- _source_cid(source_cid),
- _original_dcid(original_dcid)
+QUICConnectionId
+QUICLongHeaderPacket::source_cid() const
+{
+ return this->_scid;
+}
+uint16_t
+QUICLongHeaderPacket::payload_length() const
{
- // this->_buf_len will be set
- this->buf();
+ return this->_payload_length;
}
-QUICPacketType
-QUICPacketLongHeader::type() const
+QUICVersion
+QUICLongHeaderPacket::version() const
+{
+ return this->_version;
+}
+
+size_t
+QUICLongHeaderPacket::_write_common_header(uint8_t *buf) const
{
- if (this->_buf) {
- QUICPacketType type = QUICPacketType::UNINITIALIZED;
- QUICPacketLongHeader::type(type, this->_buf.get(), this->_buf_len);
- return type;
+ size_t n;
+ size_t len = 0;
+
+ buf[0] = 0xC0;
+ buf[0] += static_cast<uint8_t>(this->type()) << 4;
+ len += 1;
+
+ QUICTypeUtil::write_QUICVersion(this->_version, buf + len, &n);
+ len += n;
+
+ // DICD
+ if (this->_dcid != QUICConnectionId::ZERO()) {
+ // Len
+ buf[len] = this->_dcid.length();
+ len += 1;
+
+ // ID
+ QUICTypeUtil::write_QUICConnectionId(this->_dcid, buf + len, &n);
+ len += n;
+ } else {
+ buf[len] = 0;
+ len += 1;
+ }
+
+ // SCID
+ if (this->_scid != QUICConnectionId::ZERO()) {
+ // Len
+ buf[len] = this->_scid.length();
+ len += 1;
+
+ // ID
+ QUICTypeUtil::write_QUICConnectionId(this->_scid, buf + len, &n);
+ len += n;
} else {
- return this->_type;
+ buf[len] = 0;
+ len += 1;
}
+
+ return len;
}
bool
-QUICPacketLongHeader::is_crypto_packet() const
+QUICLongHeaderPacket::is_crypto_packet() const
{
return this->_is_crypto_packet;
}
+//
+// QUICLongHeaderPacketR
+//
+QUICLongHeaderPacketR::QUICLongHeaderPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks)
+ : QUICPacketR(udp_con, from, to)
+{
+ IOBufferReader reader;
+ uint8_t data[47];
+
+ reader.block = blocks;
+ int64_t data_len = reader.read(data, sizeof(data));
+
+ QUICLongHeaderPacketR::version(this->_version, data, data_len);
+}
+
+QUICVersion
+QUICLongHeaderPacketR::version() const
+{
+ return this->_version;
+}
+
+QUICConnectionId
+QUICLongHeaderPacketR::source_cid() const
+{
+ return this->_scid;
+}
+
+QUICConnectionId
+QUICLongHeaderPacketR::destination_cid() const
+{
+ return this->_dcid;
+}
+
bool
-QUICPacketLongHeader::type(QUICPacketType &type, const uint8_t *packet, size_t packet_len)
+QUICLongHeaderPacketR::type(QUICPacketType &type, const uint8_t *packet, size_t packet_len)
{
if (packet_len < 1) {
return false;
}
QUICVersion version;
- if (QUICPacketLongHeader::version(version, packet, packet_len) && version == 0x00) {
+ if (QUICLongHeaderPacketR::version(version, packet, packet_len) && version == 0x00) {
type = QUICPacketType::VERSION_NEGOTIATION;
} else {
uint8_t raw_type = (packet[0] & 0x30) >> 4;
@@ -284,7 +464,7 @@ QUICPacketLongHeader::type(QUICPacketType &type, const uint8_t *packet, size_t p
}
bool
-QUICPacketLongHeader::version(QUICVersion &version, const uint8_t *packet, size_t packet_len)
+QUICLongHeaderPacketR::version(QUICVersion &version, const uint8_t *packet, size_t packet_len)
{
if (packet_len < 5) {
return false;
@@ -295,101 +475,70 @@ QUICPacketLongHeader::version(QUICVersion &version, const uint8_t *packet, size_
}
bool
-QUICPacketLongHeader::dcil(uint8_t &dcil, const uint8_t *packet, size_t packet_len)
-{
- if (QUICInvariants::dcil(dcil, packet, packet_len)) {
- return true;
- } else {
- return false;
- }
-}
-
-bool
-QUICPacketLongHeader::scil(uint8_t &scil, const uint8_t *packet, size_t packet_len)
-{
- if (QUICInvariants::scil(scil, packet, packet_len)) {
- return true;
- } else {
- return false;
- }
-}
-
-bool
-QUICPacketLongHeader::token_length(size_t &token_length, uint8_t &field_len, size_t &token_length_filed_offset,
- const uint8_t *packet, size_t packet_len)
+QUICLongHeaderPacketR::key_phase(QUICKeyPhase &phase, const uint8_t *packet, size_t packet_len)
{
QUICPacketType type = QUICPacketType::UNINITIALIZED;
- QUICPacketLongHeader::type(type, packet, packet_len);
-
- if (type != QUICPacketType::INITIAL) {
- token_length = 0;
- field_len = 0;
-
- return true;
- }
-
- uint8_t dcil, scil;
- QUICPacketLongHeader::dcil(dcil, packet, packet_len);
- QUICPacketLongHeader::scil(scil, packet, packet_len);
-
- token_length_filed_offset = LONG_HDR_OFFSET_CONNECTION_ID + dcil + 1 + scil;
- if (token_length_filed_offset >= packet_len) {
- return false;
- }
-
- token_length = QUICIntUtil::read_QUICVariableInt(packet + token_length_filed_offset);
- field_len = QUICVariableInt::size(packet + token_length_filed_offset);
-
+ QUICLongHeaderPacketR::type(type, packet, packet_len);
+ phase = QUICTypeUtil::key_phase(type);
return true;
}
bool
-QUICPacketLongHeader::length(size_t &length, uint8_t &length_field_len, size_t &length_field_offset, const uint8_t *packet,
- size_t packet_len)
+QUICLongHeaderPacketR::length(size_t &length, uint8_t &length_field_len, size_t &length_field_offset, const uint8_t *packet,
+ size_t packet_len)
{
+ // FIXME This is not great because each packet types have different formats.
+ // We should remove this function and have length() on each packet type classes instead.
+
uint8_t dcil;
- if (!QUICPacketLongHeader::dcil(dcil, packet, packet_len)) {
+ if (!QUICInvariants::dcil(dcil, packet, packet_len)) {
return false;
}
uint8_t scil;
- if (!QUICPacketLongHeader::scil(scil, packet, packet_len)) {
+ if (!QUICInvariants::scil(scil, packet, packet_len)) {
return false;
}
- // Token Length (i) + Token (*) (for INITIAL packet)
- size_t token_length = 0;
- uint8_t token_length_field_len = 0;
- size_t token_length_field_offset = 0;
- if (!QUICPacketLongHeader::token_length(token_length, token_length_field_len, token_length_field_offset, packet, packet_len)) {
- return false;
+ length_field_offset = LONG_HDR_OFFSET_CONNECTION_ID + dcil + 1 + scil;
+
+ QUICPacketType type = QUICPacketType::UNINITIALIZED;
+ QUICLongHeaderPacketR::type(type, packet, packet_len);
+ if (type == QUICPacketType::INITIAL) {
+ // Token Length (i) + Token (*) (for INITIAL packet)
+ size_t token_length = 0;
+ uint8_t token_length_field_len = 0;
+ size_t token_length_field_offset = 0;
+ if (!QUICInitialPacketR::token_length(token_length, token_length_field_len, token_length_field_offset, packet, packet_len)) {
+ return false;
+ }
+ length_field_offset += token_length_field_len + token_length;
}
// Length (i)
- length_field_offset = LONG_HDR_OFFSET_CONNECTION_ID + dcil + 1 + scil + token_length_field_len + token_length;
if (length_field_offset >= packet_len) {
return false;
}
length_field_len = QUICVariableInt::size(packet + length_field_offset);
- length = QUICIntUtil::read_QUICVariableInt(packet + length_field_offset);
+ length = QUICIntUtil::read_QUICVariableInt(packet + length_field_offset, packet_len - length_field_offset);
return true;
}
bool
-QUICPacketLongHeader::packet_number_offset(size_t &pn_offset, const uint8_t *packet, size_t packet_len)
+QUICLongHeaderPacketR::packet_length(size_t &packet_len, const uint8_t *buf, size_t buf_len)
{
size_t length;
uint8_t length_field_len;
size_t length_field_offset;
- if (!QUICPacketLongHeader::length(length, length_field_len, length_field_offset, packet, packet_len)) {
+ if (!QUICLongHeaderPacketR::length(length, length_field_len, length_field_offset, buf, buf_len)) {
return false;
}
- pn_offset = length_field_offset + length_field_len;
+ packet_len = length + length_field_offset + length_field_len;
- if (pn_offset >= packet_len) {
+ if (packet_len > buf_len) {
return false;
}
@@ -397,639 +546,1297 @@ QUICPacketLongHeader::packet_number_offset(size_t &pn_offset, const uint8_t *pac
}
bool
-QUICPacketLongHeader::packet_length(size_t &packet_len, const uint8_t *buf, size_t buf_len)
+QUICLongHeaderPacketR::packet_number_offset(size_t &pn_offset, const uint8_t *packet, size_t packet_len)
{
- size_t length;
+ size_t dummy;
uint8_t length_field_len;
size_t length_field_offset;
- if (!QUICPacketLongHeader::length(length, length_field_len, length_field_offset, buf, buf_len)) {
+ if (!QUICLongHeaderPacketR::length(dummy, length_field_len, length_field_offset, packet, packet_len)) {
return false;
}
- packet_len = length + length_field_offset + length_field_len;
+ pn_offset = length_field_offset + length_field_len;
- if (packet_len > buf_len) {
+ if (pn_offset >= packet_len) {
return false;
}
return true;
}
-bool
-QUICPacketLongHeader::key_phase(QUICKeyPhase &phase, const uint8_t *packet, size_t packet_len)
+//
+// QUICShortHeaderPacket
+//
+QUICShortHeaderPacket::QUICShortHeaderPacket(QUICConnectionId dcid, QUICPacketNumber packet_number,
+ QUICPacketNumber base_packet_number, QUICKeyPhase key_phase, bool ack_eliciting,
+ bool probing)
+ : QUICPacket(ack_eliciting, probing), _dcid(dcid), _packet_number(packet_number), _key_phase(key_phase)
{
- QUICPacketType type = QUICPacketType::UNINITIALIZED;
- QUICPacketLongHeader::type(type, packet, packet_len);
- phase = QUICTypeUtil::key_phase(type);
- return true;
+ this->_packet_number_len = QUICPacket::calc_packet_number_len(packet_number, base_packet_number);
}
-QUICConnectionId
-QUICPacketLongHeader::destination_cid() const
+QUICPacketType
+QUICShortHeaderPacket::type() const
{
- return this->_destination_cid;
+ return QUICPacketType::PROTECTED;
}
-QUICConnectionId
-QUICPacketLongHeader::source_cid() const
+QUICKeyPhase
+QUICShortHeaderPacket::key_phase() const
{
- return this->_source_cid;
+ return this->_key_phase;
}
QUICConnectionId
-QUICPacketLongHeader::original_dcid() const
+QUICShortHeaderPacket::destination_cid() const
{
- return this->_original_dcid;
+ return this->_dcid;
}
QUICPacketNumber
-QUICPacketLongHeader::packet_number() const
+QUICShortHeaderPacket::packet_number() const
{
return this->_packet_number;
}
-bool
-QUICPacketLongHeader::has_version() const
+uint16_t
+QUICShortHeaderPacket::payload_length() const
{
- return true;
+ return this->_payload_length;
}
-bool
-QUICPacketLongHeader::is_valid() const
+Ptr<IOBufferBlock>
+QUICShortHeaderPacket::header_block() const
{
- if (this->_buf && this->_buf_len != this->_payload_offset + this->_payload_length) {
- QUICDebug(this->_source_cid, this->_destination_cid,
- "Invalid packet: packet_size(%zu) should be header_size(%zu) + payload_size(%zu)", this->_buf_len,
- this->_payload_offset, this->_payload_length);
- Warning("Invalid packet: packet_size(%zu) should be header_size(%zu) + payload_size(%zu)", this->_buf_len,
- this->_payload_offset, this->_payload_length);
+ Ptr<IOBufferBlock> block;
+ size_t written_len = 0;
- return false;
- }
+ block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ block->alloc(iobuffer_size_to_index(1 + QUICConnectionId::MAX_LENGTH + 4, BUFFER_SIZE_INDEX_32K));
+ uint8_t *buf = reinterpret_cast<uint8_t *>(block->start());
- return true;
-}
+ size_t n;
+ buf[0] = 0x40;
-QUICVersion
-QUICPacketLongHeader::version() const
-{
- if (this->_buf) {
- QUICVersion version = 0;
- QUICPacketLongHeader::version(version, this->_buf.get(), this->_buf_len);
- return version;
- } else {
- return this->_version;
- }
-}
+ // Type
+ buf[0] = 0x40;
-const uint8_t *
-QUICPacketLongHeader::payload() const
-{
- if (this->_buf) {
- uint8_t *raw = this->_buf.get();
- return raw + this->_payload_offset;
- } else {
- return this->_payload.get();
+ // TODO Spin Bit
+
+ // KeyPhase
+ if (this->_key_phase == QUICKeyPhase::PHASE_1) {
+ buf[0] |= 0x04;
}
-}
-uint16_t
-QUICPacketHeader::payload_size() const
-{
- return this->_payload_length;
-}
+ written_len += 1;
-const uint8_t *
-QUICPacketLongHeader::token() const
-{
- if (this->_buf) {
- uint8_t *raw = this->_buf.get();
- return raw + this->_token_offset;
- } else {
- return this->_token.get();
+ // Destination Connection ID
+ if (this->_dcid != QUICConnectionId::ZERO()) {
+ QUICTypeUtil::write_QUICConnectionId(this->_dcid, buf + written_len, &n);
+ written_len += n;
}
-}
-size_t
-QUICPacketLongHeader::token_len() const
-{
- return this->_token_len;
-}
+ // Packet Number
+ QUICPacketNumber dst = 0;
+ size_t dst_len = this->_packet_number_len;
+ QUICPacket::encode_packet_number(dst, this->_packet_number, dst_len);
+ QUICTypeUtil::write_QUICPacketNumber(dst, dst_len, buf + written_len, &n);
+ written_len += n;
-QUICKeyPhase
-QUICPacketLongHeader::key_phase() const
-{
- return this->_key_phase;
+ // Packet Number Length
+ QUICTypeUtil::write_QUICPacketNumberLen(n, buf);
+
+ block->fill(written_len);
+
+ return block;
}
-uint16_t
-QUICPacketLongHeader::size() const
+Ptr<IOBufferBlock>
+QUICShortHeaderPacket::payload_block() const
{
- return this->_buf_len - this->_payload_length;
+ return this->_payload_block;
}
void
-QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const
+QUICShortHeaderPacket::attach_payload(Ptr<IOBufferBlock> payload, bool unprotected)
+{
+ this->_payload_block = payload;
+ this->_payload_length = 0;
+ Ptr<IOBufferBlock> tmp = payload;
+ while (tmp) {
+ this->_payload_length += tmp->size();
+ tmp = tmp->next;
+ }
+ if (unprotected) {
+ this->_payload_length += aead_tag_len;
+ }
+}
+
+//
+// QUICShortHeaderPacketR
+//
+QUICShortHeaderPacketR::QUICShortHeaderPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks,
+ QUICPacketNumber base_packet_number)
+ : QUICPacketR(udp_con, from, to)
{
- size_t n;
- *len = 0;
- buf[0] = 0xC0;
- buf[0] += static_cast<uint8_t>(this->_type) << 4;
- if (this->_type == QUICPacketType::VERSION_NEGOTIATION) {
- buf[0] |= rand();
+ size_t len = 0;
+ for (auto b = blocks; b; b = b->next) {
+ len += b->size();
}
- *len += 1;
- QUICTypeUtil::write_QUICVersion(this->_version, buf + *len, &n);
- *len += n;
+ Ptr<IOBufferBlock> concatinated_block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ concatinated_block->alloc(iobuffer_size_to_index(len, BUFFER_SIZE_INDEX_32K));
+ concatinated_block->fill(len);
- // DICD
- if (this->_destination_cid != QUICConnectionId::ZERO()) {
- // Len
- buf[*len] = this->_destination_cid.length();
- *len += 1;
+ uint8_t *raw_buf = reinterpret_cast<uint8_t *>(concatinated_block->start());
- // ID
- QUICTypeUtil::write_QUICConnectionId(this->_destination_cid, buf + *len, &n);
- *len += n;
- } else {
- buf[*len] = 0;
- *len += 1;
+ size_t copied_len = 0;
+ for (auto b = blocks; b; b = b->next) {
+ memcpy(raw_buf + copied_len, b->start(), b->size());
+ copied_len += b->size();
}
- // SCID
- if (this->_source_cid != QUICConnectionId::ZERO()) {
- // Len
- buf[*len] = this->_source_cid.length();
- *len += 1;
-
- // ID
- QUICTypeUtil::write_QUICConnectionId(this->_source_cid, buf + *len, &n);
- *len += n;
+ if (raw_buf[0] & 0x04) {
+ this->_key_phase = QUICKeyPhase::PHASE_1;
} else {
- buf[*len] = 0;
- *len += 1;
+ this->_key_phase = QUICKeyPhase::PHASE_0;
}
- if (this->_type != QUICPacketType::VERSION_NEGOTIATION) {
- if (this->_type == QUICPacketType::RETRY) {
- // Original Destination Connection ID
- if (this->_original_dcid != QUICConnectionId::ZERO()) {
- // Len
- buf[*len] = this->_original_dcid.length();
- *len += 1;
-
- // ID
- QUICTypeUtil::write_QUICConnectionId(this->_original_dcid, buf + *len, &n);
- *len += n;
- } else {
- buf[*len] = 0;
- *len += 1;
- }
- } else {
- if (this->_type == QUICPacketType::INITIAL) {
- // Token Length Field
- QUICIntUtil::write_QUICVariableInt(this->_token_len, buf + *len, &n);
- *len += n;
-
- // Token Field
- memcpy(buf + *len, this->token(), this->token_len());
- *len += this->token_len();
- }
-
- QUICPacketNumber pn = 0;
- size_t pn_len = 4;
- QUICPacket::encode_packet_number(pn, this->_packet_number, pn_len);
-
- if (pn > 0x7FFFFF) {
- pn_len = 4;
- } else if (pn > 0x7FFF) {
- pn_len = 3;
- } else if (pn > 0x7F) {
- pn_len = 2;
- } else {
- pn_len = 1;
- }
-
- if (this->_type != QUICPacketType::RETRY) {
- // PN Len field
- QUICTypeUtil::write_QUICPacketNumberLen(pn_len, buf);
- }
-
- // Length Field
- QUICIntUtil::write_QUICVariableInt(pn_len + this->_payload_length + aead_tag_len, buf + *len, &n);
- *len += n;
+ QUICInvariants::dcid(this->_dcid, raw_buf, len);
- // PN Field
- QUICTypeUtil::write_QUICPacketNumber(pn, pn_len, buf + *len, &n);
- *len += n;
- }
+ int offset = 1 + this->_dcid.length();
+ this->_packet_number_len = QUICTypeUtil::read_QUICPacketNumberLen(raw_buf);
+ QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(raw_buf + offset, this->_packet_number_len);
+ QUICPacket::decode_packet_number(this->_packet_number, src, this->_packet_number_len, base_packet_number);
+ offset += this->_packet_number_len;
- // Payload will be stored
- }
+ this->_header_block = concatinated_block->clone();
+ this->_header_block->_end = this->_header_block->_start + offset;
+ this->_header_block->next = nullptr;
+ this->_payload_block = concatinated_block->clone();
+ this->_payload_block->_start = this->_payload_block->_start + offset;
}
-//
-// QUICPacketShortHeader
-//
-
-QUICPacketShortHeader::QUICPacketShortHeader(const IpEndpoint from, const IpEndpoint to, ats_unique_buf buf, size_t len,
- QUICPacketNumber base)
- : QUICPacketHeader(from, to, std::move(buf), len, base)
+QUICPacketType
+QUICShortHeaderPacketR::type() const
{
- QUICInvariants::dcid(this->_connection_id, this->_buf.get(), len);
-
- int offset = 1 + this->_connection_id.length();
- this->_packet_number_len = QUICTypeUtil::read_QUICPacketNumberLen(this->_buf.get());
- QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(this->_buf.get() + offset, this->_packet_number_len);
- QUICPacket::decode_packet_number(this->_packet_number, src, this->_packet_number_len, this->_base_packet_number);
- this->_payload_length = len - (1 + QUICConnectionId::SCID_LEN + this->_packet_number_len);
+ return QUICPacketType::PROTECTED;
}
-QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICPacketNumber packet_number,
- QUICPacketNumber base_packet_number, ats_unique_buf buf, size_t len)
+QUICKeyPhase
+QUICShortHeaderPacketR::key_phase() const
{
- this->_type = type;
- this->_key_phase = key_phase;
- this->_packet_number = packet_number;
- this->_base_packet_number = base_packet_number;
- this->_packet_number_len = QUICPacket::calc_packet_number_len(packet_number, base_packet_number);
- this->_payload = std::move(buf);
- this->_payload_length = len;
+ return this->_key_phase;
}
-QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase key_phase, const QUICConnectionId &connection_id,
- QUICPacketNumber packet_number, QUICPacketNumber base_packet_number,
- ats_unique_buf buf, size_t len)
+QUICPacketNumber
+QUICShortHeaderPacketR::packet_number() const
{
- this->_type = type;
- this->_key_phase = key_phase;
- this->_connection_id = connection_id;
- this->_packet_number = packet_number;
- this->_base_packet_number = base_packet_number;
- this->_packet_number_len = QUICPacket::calc_packet_number_len(packet_number, base_packet_number);
- this->_payload = std::move(buf);
- this->_payload_length = len;
+ return this->_packet_number;
}
-QUICPacketType
-QUICPacketShortHeader::type() const
+QUICConnectionId
+QUICShortHeaderPacketR::destination_cid() const
{
- QUICKeyPhase key_phase = this->key_phase();
-
- switch (key_phase) {
- case QUICKeyPhase::PHASE_0: {
- return QUICPacketType::PROTECTED;
- }
- case QUICKeyPhase::PHASE_1: {
- return QUICPacketType::PROTECTED;
- }
- default:
- return QUICPacketType::STATELESS_RESET;
- }
+ return this->_dcid;
}
-QUICConnectionId
-QUICPacketShortHeader::destination_cid() const
+Ptr<IOBufferBlock>
+QUICShortHeaderPacketR::header_block() const
{
- if (this->_buf) {
- QUICConnectionId dcid = QUICConnectionId::ZERO();
- QUICInvariants::dcid(dcid, this->_buf.get(), this->_buf_len);
- return dcid;
- } else {
- return _connection_id;
- }
+ return this->_header_block;
}
-QUICPacketNumber
-QUICPacketShortHeader::packet_number() const
+Ptr<IOBufferBlock>
+QUICShortHeaderPacketR::payload_block() const
{
- return this->_packet_number;
+ return this->_payload_block;
}
-bool
-QUICPacketShortHeader::has_version() const
+void
+QUICShortHeaderPacketR::attach_payload(Ptr<IOBufferBlock> payload, bool unprotected)
{
- return false;
+ this->_payload_block = payload;
}
bool
-QUICPacketShortHeader::is_valid() const
+QUICShortHeaderPacketR::packet_number_offset(size_t &pn_offset, const uint8_t *packet, size_t packet_len, int dcil)
{
+ pn_offset = 1 + dcil;
return true;
}
-QUICVersion
-QUICPacketShortHeader::version() const
+//
+// QUICStatelessResetPacket
+//
+QUICStatelessResetPacket::QUICStatelessResetPacket(QUICStatelessResetToken token, size_t maximum_size)
+ : QUICPacket(), _token(token), _maximum_size(maximum_size)
{
- return 0;
}
-const uint8_t *
-QUICPacketShortHeader::payload() const
+QUICPacketType
+QUICStatelessResetPacket::type() const
{
- if (this->_buf) {
- return this->_buf.get() + this->size();
- } else {
- return this->_payload.get();
- }
+ return QUICPacketType::STATELESS_RESET;
}
-QUICKeyPhase
-QUICPacketShortHeader::key_phase() const
+QUICConnectionId
+QUICStatelessResetPacket::destination_cid() const
{
- if (this->_buf) {
- QUICKeyPhase phase = QUICKeyPhase::INITIAL;
- QUICPacketShortHeader::key_phase(phase, this->_buf.get(), this->_buf_len);
- return phase;
- } else {
- return this->_key_phase;
- }
+ ink_assert(!"You should not need DCID of Stateless Reset Packet");
+ return QUICConnectionId::ZERO();
}
-bool
-QUICPacketShortHeader::key_phase(QUICKeyPhase &phase, const uint8_t *packet, size_t packet_len)
+Ptr<IOBufferBlock>
+QUICStatelessResetPacket::header_block() const
{
- if (packet_len < 1) {
- return false;
+ // Required shortest length is 38 bits however less than 41 bytes in total indicates this is stateless reset.
+ constexpr uint8_t MIN_UNPREDICTABLE_FIELD_LEN = 5 + 20;
+
+ std::random_device rnd;
+
+ Ptr<IOBufferBlock> block;
+ size_t written_len = 0;
+
+ size_t random_extra_length = rnd() & 0x07; // Extra 0 to 7 bytes
+
+ if (MIN_UNPREDICTABLE_FIELD_LEN + random_extra_length > this->_maximum_size) {
+ return block;
}
- if (packet[0] & 0x04) {
- phase = QUICKeyPhase::PHASE_1;
- } else {
- phase = QUICKeyPhase::PHASE_0;
+
+ block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ block->alloc(iobuffer_size_to_index(MIN_UNPREDICTABLE_FIELD_LEN + random_extra_length, BUFFER_SIZE_INDEX_32K));
+ uint8_t *buf = reinterpret_cast<uint8_t *>(block->start());
+
+ // Generate random octets
+ for (int i = 0; i < MIN_UNPREDICTABLE_FIELD_LEN; ++i) {
+ buf[i] = static_cast<uint8_t>(rnd() & 0xFF);
}
- return true;
+ buf[0] = (buf[0] | 0x40) & 0x7f;
+ written_len += MIN_UNPREDICTABLE_FIELD_LEN;
+
+ block->fill(written_len);
+
+ return block;
}
-bool
-QUICPacketShortHeader::packet_number_offset(size_t &pn_offset, const uint8_t *packet, size_t packet_len, int dcil)
+Ptr<IOBufferBlock>
+QUICStatelessResetPacket::payload_block() const
{
- pn_offset = 1 + dcil;
- return true;
+ Ptr<IOBufferBlock> block;
+ size_t written_len = 0;
+
+ block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ block->alloc(iobuffer_size_to_index(QUICStatelessResetToken::LEN, BUFFER_SIZE_INDEX_32K));
+ uint8_t *buf = reinterpret_cast<uint8_t *>(block->start());
+
+ memcpy(buf, this->_token.buf(), QUICStatelessResetToken::LEN);
+ written_len += QUICStatelessResetToken::LEN;
+
+ block->fill(written_len);
+
+ return block;
}
-/**
- * Header Length (doesn't include payload length)
- */
-uint16_t
-QUICPacketShortHeader::size() const
+QUICPacketNumber
+QUICStatelessResetPacket::packet_number() const
{
- uint16_t len = 1;
- if (this->_connection_id != QUICConnectionId::ZERO()) {
- len += this->_connection_id.length();
- }
- len += this->_packet_number_len;
+ ink_assert(!"You should not need packet number of Stateless Reset Packet");
+ return 0;
+}
- return len;
+QUICStatelessResetToken
+QUICStatelessResetPacket::token() const
+{
+ return this->_token;
}
-void
-QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const
+//
+// QUICStatelessResetPacketR
+//
+QUICStatelessResetPacketR::QUICStatelessResetPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to,
+ Ptr<IOBufferBlock> blocks)
+ : QUICPacketR(udp_con, from, to)
{
- size_t n;
- *len = 0;
- buf[0] = 0x40;
- if (this->_key_phase == QUICKeyPhase::PHASE_1) {
- buf[0] |= 0x04;
- }
- *len += 1;
+}
- if (this->_connection_id != QUICConnectionId::ZERO()) {
- QUICTypeUtil::write_QUICConnectionId(this->_connection_id, buf + *len, &n);
- *len += n;
- }
+QUICPacketType
+QUICStatelessResetPacketR::type() const
+{
+ return QUICPacketType::STATELESS_RESET;
+}
- QUICPacketNumber dst = 0;
- size_t dst_len = this->_packet_number_len;
- QUICPacket::encode_packet_number(dst, this->_packet_number, dst_len);
- QUICTypeUtil::write_QUICPacketNumber(dst, dst_len, buf + *len, &n);
- *len += n;
+QUICPacketNumber
+QUICStatelessResetPacketR::packet_number() const
+{
+ ink_assert(!"You should not need packet number of Stateless Reset Packet");
+ return 0;
+}
- QUICTypeUtil::write_QUICPacketNumberLen(n, buf);
+QUICConnectionId
+QUICStatelessResetPacketR::destination_cid() const
+{
+ ink_assert(!"You should not need DCID of Stateless Reset Packet");
+ return QUICConnectionId::ZERO();
}
//
-// QUICPacket
+// QUICVersionNegotiationPacket
//
-
-QUICPacket::QUICPacket() {}
-
-QUICPacket::QUICPacket(UDPConnection *udp_con, QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len)
- : _udp_con(udp_con), _header(std::move(header)), _payload(std::move(payload)), _payload_size(payload_len)
+QUICVersionNegotiationPacket::QUICVersionNegotiationPacket(QUICConnectionId dcid, QUICConnectionId scid,
+ const QUICVersion versions[], int nversions)
+ : QUICLongHeaderPacket(0, dcid, scid, false, false, false), _versions(versions), _nversions(nversions)
{
}
-QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool ack_eliciting, bool probing)
- : _header(std::move(header)),
- _payload(std::move(payload)),
- _payload_size(payload_len),
- _is_ack_eliciting(ack_eliciting),
- _is_probing_packet(probing)
+QUICPacketType
+QUICVersionNegotiationPacket::type() const
{
+ return QUICPacketType::VERSION_NEGOTIATION;
}
-QUICPacket::~QUICPacket()
+QUICVersion
+QUICVersionNegotiationPacket::version() const
{
- this->_header = nullptr;
+ return 0;
}
-const IpEndpoint &
-QUICPacket::from() const
+QUICPacketNumber
+QUICVersionNegotiationPacket::packet_number() const
{
- return this->_header->from();
+ ink_assert(!"You should not need packet number of Version Negotiation Packet");
+ return 0;
}
-const IpEndpoint &
-QUICPacket::to() const
+uint16_t
+QUICVersionNegotiationPacket::payload_length() const
{
- return this->_header->to();
+ uint16_t size = 0;
+
+ for (auto b = this->payload_block(); b; b = b->next) {
+ size += b->size();
+ }
+
+ return size;
}
-UDPConnection *
-QUICPacket::udp_con() const
+Ptr<IOBufferBlock>
+QUICVersionNegotiationPacket::header_block() const
{
- return this->_udp_con;
+ Ptr<IOBufferBlock> block;
+ size_t written_len = 0;
+
+ block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ block->alloc(iobuffer_size_to_index(2048, BUFFER_SIZE_INDEX_32K));
+ uint8_t *buf = reinterpret_cast<uint8_t *>(block->start());
+
+ // Common Long Header
+ written_len += this->_write_common_header(buf + written_len);
+
+ // Overwrite the first byte
+ buf[0] = 0x80 | rand();
+
+ block->fill(written_len);
+
+ return block;
}
-/**
- * When packet is "Short Header Packet", QUICPacket::type() will return 1-RTT Protected (key phase 0)
- * or 1-RTT Protected (key phase 1)
- */
-QUICPacketType
-QUICPacket::type() const
+Ptr<IOBufferBlock>
+QUICVersionNegotiationPacket::payload_block() const
{
- return this->_header->type();
+ Ptr<IOBufferBlock> block;
+ uint8_t *buf;
+ size_t written_len = 0;
+ size_t n;
+
+ block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ block->alloc(iobuffer_size_to_index(sizeof(QUICVersion) * (this->_nversions + 1), BUFFER_SIZE_INDEX_32K));
+ buf = reinterpret_cast<uint8_t *>(block->start());
+
+ for (auto i = 0; i < this->_nversions; ++i) {
+ QUICTypeUtil::write_QUICVersion(*(this->_versions + i), buf + written_len, &n);
+ written_len += n;
+ }
+
+ // [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);
+ written_len += n;
+
+ block->fill(written_len);
+
+ return block;
}
-QUICConnectionId
-QUICPacket::destination_cid() const
+const QUICVersion *
+QUICVersionNegotiationPacket::versions() const
{
- return this->_header->destination_cid();
+ return this->_versions;
}
-QUICConnectionId
-QUICPacket::source_cid() const
+int
+QUICVersionNegotiationPacket::nversions() const
{
- return this->_header->source_cid();
+ return this->_nversions;
}
-QUICPacketNumber
-QUICPacket::packet_number() const
+//
+// QUICVersionNegotiationPacketR
+//
+QUICVersionNegotiationPacketR::QUICVersionNegotiationPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to,
+ Ptr<IOBufferBlock> blocks)
+ : QUICLongHeaderPacketR(udp_con, from, to, blocks)
{
- return this->_header->packet_number();
+ size_t len = 0;
+ for (auto b = blocks; b; b = b->next) {
+ len += b->size();
+ }
+
+ Ptr<IOBufferBlock> concatinated_block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ concatinated_block->alloc(iobuffer_size_to_index(len, BUFFER_SIZE_INDEX_32K));
+ concatinated_block->fill(len);
+
+ uint8_t *raw_buf = reinterpret_cast<uint8_t *>(concatinated_block->start());
+
+ size_t copied_len = 0;
+ for (auto b = blocks; b; b = b->next) {
+ memcpy(raw_buf + copied_len, b->start(), b->size());
+ copied_len += b->size();
+ }
+
+ uint8_t dcil = 0;
+ uint8_t scil = 0;
+ QUICInvariants::dcil(dcil, raw_buf, len);
+ QUICInvariants::scil(scil, raw_buf, len);
+
+ size_t offset = LONG_HDR_OFFSET_CONNECTION_ID;
+ this->_dcid = {raw_buf + offset, dcil};
+ offset += dcil + 1;
+ this->_scid = {raw_buf + offset, scil};
+ offset += scil;
+
+ this->_versions = raw_buf + offset;
+ this->_nversions = (len - offset) / sizeof(QUICVersion);
+
+ this->_header_block = concatinated_block->clone();
+ this->_header_block->_end = this->_header_block->_start + offset;
+ this->_header_block->next = nullptr;
+ this->_payload_block = concatinated_block->clone();
+ this->_payload_block->_start = this->_payload_block->_start + offset;
}
-bool
-QUICPacket::is_crypto_packet() const
+QUICPacketType
+QUICVersionNegotiationPacketR::type() const
{
- return this->_header->is_crypto_packet();
+ return QUICPacketType::VERSION_NEGOTIATION;
}
-const QUICPacketHeader &
-QUICPacket::header() const
+QUICPacketNumber
+QUICVersionNegotiationPacketR::packet_number() const
{
- return *this->_header;
+ ink_assert(!"You should not need packet number of Version Negotiation Packet");
+ return 0;
}
-const uint8_t *
-QUICPacket::payload() const
+QUICConnectionId
+QUICVersionNegotiationPacketR::destination_cid() const
{
- return this->_payload.get();
+ return this->_dcid;
}
-QUICVersion
-QUICPacket::version() const
+Ptr<IOBufferBlock>
+QUICVersionNegotiationPacketR::header_block() const
{
- return this->_header->version();
+ return this->_header_block;
}
-bool
-QUICPacket::is_ack_eliciting() const
+Ptr<IOBufferBlock>
+QUICVersionNegotiationPacketR::payload_block() const
{
- return this->_is_ack_eliciting;
+ return this->_payload_block;
}
-bool
-QUICPacket::is_probing_packet() const
+const QUICVersion
+QUICVersionNegotiationPacketR::supported_version(uint8_t index) const
{
- return this->_is_probing_packet;
+ return QUICTypeUtil::read_QUICVersion(this->_versions + sizeof(QUICVersion) * index);
}
-uint16_t
-QUICPacket::size() const
+int
+QUICVersionNegotiationPacketR::nversions() const
{
- // This includes not only header size and payload size but also AEAD tag length
- uint16_t size = this->_header->packet_size();
- if (size == 0) {
- size = this->header_size() + this->payload_length();
- }
- return size;
+ return this->_nversions;
}
-uint16_t
-QUICPacket::header_size() const
+//
+// QUICInitialPacket
+//
+QUICInitialPacket::QUICInitialPacket(QUICVersion version, QUICConnectionId dcid, QUICConnectionId scid, size_t token_len,
+ ats_unique_buf token, size_t length, QUICPacketNumber packet_number, bool ack_eliciting,
+ bool probing, bool crypto)
+ : QUICLongHeaderPacket(version, dcid, scid, ack_eliciting, probing, crypto),
+ _token_len(token_len),
+ _token(std::move(token)),
+ _packet_number(packet_number)
{
- return this->_header->size();
}
-uint16_t
-QUICPacket::payload_length() const
+QUICPacketType
+QUICInitialPacket::type() const
{
- return this->_payload_size;
+ return QUICPacketType::INITIAL;
}
QUICKeyPhase
-QUICPacket::key_phase() const
+QUICInitialPacket::key_phase() const
{
- return this->_header->key_phase();
+ return QUICKeyPhase::INITIAL;
}
-void
-QUICPacket::store(uint8_t *buf, size_t *len) const
+QUICPacketNumber
+QUICInitialPacket::packet_number() const
{
- memcpy(buf, this->_header->buf(), this->_header->size());
- memcpy(buf + this->_header->size(), this->payload(), this->payload_length());
- *len = this->_header->size() + this->payload_length();
+ return this->_packet_number;
}
-uint8_t
-QUICPacket::calc_packet_number_len(QUICPacketNumber num, QUICPacketNumber base)
+Ptr<IOBufferBlock>
+QUICInitialPacket::header_block() const
{
- uint64_t d = (num - base) * 2;
- uint8_t len = 0;
+ Ptr<IOBufferBlock> block;
+ size_t written_len = 0;
+ size_t n;
- if (d > 0xFFFFFF) {
- len = 4;
- } else if (d > 0xFFFF) {
- len = 3;
- } else if (d > 0xFF) {
- len = 2;
+ block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ block->alloc(iobuffer_size_to_index(2048, BUFFER_SIZE_INDEX_32K));
+ uint8_t *buf = reinterpret_cast<uint8_t *>(block->start());
+
+ // Common Long Header
+ written_len += this->_write_common_header(buf + written_len);
+
+ // Token Length
+ QUICIntUtil::write_QUICVariableInt(this->_token_len, buf + written_len, &n);
+ written_len += n;
+
+ // Token
+ memcpy(buf + written_len, this->_token.get(), this->_token_len);
+ written_len += this->_token_len;
+
+ QUICPacketNumber pn = 0;
+ size_t pn_len = 4;
+ QUICPacket::encode_packet_number(pn, this->_packet_number, pn_len);
+
+ if (pn > 0x7FFFFF) {
+ pn_len = 4;
+ } else if (pn > 0x7FFF) {
+ pn_len = 3;
+ } else if (pn > 0x7F) {
+ pn_len = 2;
} else {
- len = 1;
+ pn_len = 1;
}
- return len;
+ // PN Len
+ QUICTypeUtil::write_QUICPacketNumberLen(pn_len, buf);
+
+ // Length
+ QUICIntUtil::write_QUICVariableInt(pn_len + this->_payload_length, buf + written_len, &n);
+ written_len += n;
+
+ // PN Field
+ QUICTypeUtil::write_QUICPacketNumber(pn, pn_len, buf + written_len, &n);
+ written_len += n;
+
+ block->fill(written_len);
+
+ return block;
+}
+
+Ptr<IOBufferBlock>
+QUICInitialPacket::payload_block() const
+{
+ return this->_payload_block;
+}
+
+void
+QUICInitialPacket::attach_payload(Ptr<IOBufferBlock> payload, bool unprotected)
+{
+ this->_payload_block = payload;
+ this->_payload_length = 0;
+ Ptr<IOBufferBlock> tmp = payload;
+ while (tmp) {
+ this->_payload_length += tmp->size();
+ tmp = tmp->next;
+ }
+ if (unprotected) {
+ this->_payload_length += aead_tag_len;
+ }
+}
+
+//
+// QUICInitialPacketR
+//
+QUICInitialPacketR::QUICInitialPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks,
+ QUICPacketNumber base_packet_number)
+ : QUICLongHeaderPacketR(udp_con, from, to, blocks)
+{
+ size_t len = 0;
+ for (auto b = blocks; b; b = b->next) {
+ len += b->size();
+ }
+
+ Ptr<IOBufferBlock> concatinated_block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ concatinated_block->alloc(iobuffer_size_to_index(len, BUFFER_SIZE_INDEX_32K));
+ concatinated_block->fill(len);
+
+ uint8_t *raw_buf = reinterpret_cast<uint8_t *>(concatinated_block->start());
+
+ size_t copied_len = 0;
+ for (auto b = blocks; b; b = b->next) {
+ memcpy(raw_buf + copied_len, b->start(), b->size());
+ copied_len += b->size();
+ }
+
+ uint8_t dcil = 0;
+ uint8_t scil = 0;
+ QUICInvariants::dcil(dcil, raw_buf, len);
+ QUICInvariants::scil(scil, raw_buf, len);
+
+ size_t offset = LONG_HDR_OFFSET_CONNECTION_ID;
+ this->_dcid = {raw_buf + offset, dcil};
+ offset += dcil + 1;
+ this->_scid = {raw_buf + offset, scil};
+ offset += scil;
+
+ // Token Length Field
+ uint64_t token_len = QUICIntUtil::read_QUICVariableInt(raw_buf + offset, len - offset);
+ offset += QUICVariableInt::size(raw_buf + offset);
+
+ // Token Field
+ if (token_len) {
+ this->_token = new QUICAddressValidationToken(raw_buf + offset, token_len);
+ offset += token_len;
+ } else {
+ this->_token = new QUICAddressValidationToken(nullptr, 0);
+ }
+
+ // Length Field
+ offset += QUICVariableInt::size(raw_buf + offset);
+
+ // PN Field
+ int pn_len = QUICTypeUtil::read_QUICPacketNumberLen(raw_buf);
+ QUICPacket::decode_packet_number(this->_packet_number, QUICTypeUtil::read_QUICPacketNumber(raw_buf + offset, pn_len), pn_len,
+ base_packet_number);
+ offset += pn_len;
+
+ this->_header_block = concatinated_block->clone();
+ this->_header_block->_end = this->_header_block->_start + offset;
+ this->_header_block->next = nullptr;
+ this->_payload_block = concatinated_block->clone();
+ this->_payload_block->_start = this->_payload_block->_start + offset;
+}
+
+QUICInitialPacketR::~QUICInitialPacketR()
+{
+ delete this->_token;
+}
+
+QUICPacketType
+QUICInitialPacketR::type() const
+{
+ return QUICPacketType::INITIAL;
+}
+
+QUICPacketNumber
+QUICInitialPacketR::packet_number() const
+{
+ return this->_packet_number;
+}
+
+QUICKeyPhase
+QUICInitialPacketR::key_phase() const
+{
+ return QUICKeyPhase::INITIAL;
+}
+
+Ptr<IOBufferBlock>
+QUICInitialPacketR::header_block() const
+{
+ return this->_header_block;
+}
+
+Ptr<IOBufferBlock>
+QUICInitialPacketR::payload_block() const
+{
+ return this->_payload_block;
+}
+
+void
+QUICInitialPacketR::attach_payload(Ptr<IOBufferBlock> payload, bool unprotected)
+{
+ this->_payload_block = payload;
+}
+
+const QUICAddressValidationToken &
+QUICInitialPacketR::token() const
+{
+ return *(this->_token);
}
bool
-QUICPacket::encode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len)
+QUICInitialPacketR::token_length(size_t &token_length, uint8_t &field_len, size_t &token_length_filed_offset, const uint8_t *packet,
+ size_t packet_len)
{
- uint64_t mask = 0;
- switch (len) {
- case 1:
- mask = 0xFF;
- break;
- case 2:
- mask = 0xFFFF;
- break;
- case 3:
- mask = 0xFFFFFF;
- break;
- case 4:
- mask = 0xFFFFFFFF;
- break;
- default:
- ink_assert(!"len must be 1, 2, or 4");
+ QUICPacketType type = QUICPacketType::UNINITIALIZED;
+ QUICPacketR::type(type, packet, packet_len);
+
+ ink_assert(type == QUICPacketType::INITIAL);
+
+ uint8_t dcil, scil;
+ QUICInvariants::dcil(dcil, packet, packet_len);
+ QUICInvariants::scil(scil, packet, packet_len);
+
+ token_length_filed_offset = LONG_HDR_OFFSET_CONNECTION_ID + dcil + 1 + scil;
+ if (token_length_filed_offset >= packet_len) {
return false;
}
- dst = src & mask;
+
+ token_length = QUICIntUtil::read_QUICVariableInt(packet + token_length_filed_offset, packet_len - token_length_filed_offset);
+ field_len = QUICVariableInt::size(packet + token_length_filed_offset);
return true;
}
-bool
-QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len, QUICPacketNumber largest_acked)
+//
+// QUICZeroRttPacket
+//
+QUICZeroRttPacket::QUICZeroRttPacket(QUICVersion version, QUICConnectionId dcid, QUICConnectionId scid, size_t length,
+ QUICPacketNumber packet_number, bool ack_eliciting, bool probing)
+ : QUICLongHeaderPacket(version, dcid, scid, ack_eliciting, probing, false), _packet_number(packet_number)
{
- ink_assert(len == 1 || len == 2 || len == 3 || len == 4);
+}
- uint64_t maximum_diff = 0;
- switch (len) {
- case 1:
- maximum_diff = 0x100;
- break;
- case 2:
- maximum_diff = 0x10000;
- break;
- case 3:
- maximum_diff = 0x1000000;
- break;
- case 4:
- maximum_diff = 0x100000000;
- break;
- default:
- ink_assert(!"len must be 1, 2, 3 or 4");
+QUICPacketType
+QUICZeroRttPacket::type() const
+{
+ return QUICPacketType::ZERO_RTT_PROTECTED;
+}
+
+QUICKeyPhase
+QUICZeroRttPacket::key_phase() const
+{
+ return QUICKeyPhase::ZERO_RTT;
+}
+
+QUICPacketNumber
+QUICZeroRttPacket::packet_number() const
+{
+ return this->_packet_number;
+}
+
+Ptr<IOBufferBlock>
+QUICZeroRttPacket::header_block() const
+{
+ Ptr<IOBufferBlock> block;
+ size_t written_len = 0;
+ size_t n;
+
+ block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ block->alloc(iobuffer_size_to_index(2048, BUFFER_SIZE_INDEX_32K));
+ uint8_t *buf = reinterpret_cast<uint8_t *>(block->start());
+
+ // Common Long Header
+ written_len += this->_write_common_header(buf + written_len);
+
+ QUICPacketNumber pn = 0;
+ size_t pn_len = 4;
+ QUICPacket::encode_packet_number(pn, this->_packet_number, pn_len);
+
+ if (pn > 0x7FFFFF) {
+ pn_len = 4;
+ } else if (pn > 0x7FFF) {
+ pn_len = 3;
+ } else if (pn > 0x7F) {
+ pn_len = 2;
+ } else {
+ pn_len = 1;
}
- QUICPacketNumber base = largest_acked & (~(maximum_diff - 1));
- QUICPacketNumber candidate1 = base + src;
- QUICPacketNumber candidate2 = base + src + maximum_diff;
- QUICPacketNumber expected = largest_acked + 1;
- if (((candidate1 > expected) ? (candidate1 - expected) : (expected - candidate1)) <
- ((candidate2 > expected) ? (candidate2 - expected) : (expected - candidate2))) {
- dst = candidate1;
+ // PN Len
+ QUICTypeUtil::write_QUICPacketNumberLen(pn_len, buf);
+
+ // Length
+ QUICIntUtil::write_QUICVariableInt(pn_len + this->_payload_length, buf + written_len, &n);
+ written_len += n;
+
+ // PN Field
+ QUICTypeUtil::write_QUICPacketNumber(pn, pn_len, buf + written_len, &n);
+ written_len += n;
+
+ block->fill(written_len);
+
+ return block;
+}
+
+Ptr<IOBufferBlock>
+QUICZeroRttPacket::payload_block() const
+{
+ return this->_payload_block;
+}
+
+void
+QUICZeroRttPacket::attach_payload(Ptr<IOBufferBlock> payload, bool unprotected)
+{
+ this->_payload_block = payload;
+ this->_payload_length = 0;
+ Ptr<IOBufferBlock> tmp = payload;
+ while (tmp) {
+ this->_payload_length += tmp->size();
+ tmp = tmp->next;
+ }
+ if (unprotected) {
+ this->_payload_length += aead_tag_len;
+ }
+}
+
+//
+// QUICZeroRttPacketR
+//
+QUICZeroRttPacketR::QUICZeroRttPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks,
+ QUICPacketNumber base_packet_number)
+ : QUICLongHeaderPacketR(udp_con, from, to, blocks)
+{
+ size_t len = 0;
+ for (auto b = blocks; b; b = b->next) {
+ len += b->size();
+ }
+
+ Ptr<IOBufferBlock> concatinated_block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ concatinated_block->alloc(iobuffer_size_to_index(len, BUFFER_SIZE_INDEX_32K));
+ concatinated_block->fill(len);
+
+ uint8_t *raw_buf = reinterpret_cast<uint8_t *>(concatinated_block->start());
+
+ size_t copied_len = 0;
+ for (auto b = blocks; b; b = b->next) {
+ memcpy(raw_buf + copied_len, b->start(), b->size());
+ copied_len += b->size();
+ }
+
+ uint8_t dcil = 0;
+ uint8_t scil = 0;
+ QUICInvariants::dcil(dcil, raw_buf, len);
+ QUICInvariants::scil(scil, raw_buf, len);
+
+ size_t offset = LONG_HDR_OFFSET_CONNECTION_ID;
+ this->_dcid = {raw_buf + offset, dcil};
+ offset += dcil + 1;
+ this->_scid = {raw_buf + offset, scil};
+ offset += scil;
+
+ // Length Field
+ offset += QUICVariableInt::size(raw_buf + offset);
+
+ // PN Field
+ int pn_len = QUICTypeUtil::read_QUICPacketNumberLen(raw_buf);
+ QUICPacket::decode_packet_number(this->_packet_number, QUICTypeUtil::read_QUICPacketNumber(raw_buf + offset, pn_len), pn_len,
+ base_packet_number);
+ offset += pn_len;
+
+ this->_header_block = concatinated_block->clone();
+ this->_header_block->_end = this->_header_block->_start + offset;
+ this->_header_block->next = nullptr;
+ this->_payload_block = concatinated_block->clone();
+ this->_payload_block->_start = this->_payload_block->_start + offset;
+}
+
+QUICPacketType
+QUICZeroRttPacketR::type() const
+{
+ return QUICPacketType::ZERO_RTT_PROTECTED;
+}
+
+QUICPacketNumber
+QUICZeroRttPacketR::packet_number() const
+{
+ return this->_packet_number;
+}
+
+QUICKeyPhase
+QUICZeroRttPacketR::key_phase() const
+{
+ return QUICKeyPhase::ZERO_RTT;
+}
+
+Ptr<IOBufferBlock>
+QUICZeroRttPacketR::header_block() const
+{
+ return this->_header_block;
+}
+
+Ptr<IOBufferBlock>
+QUICZeroRttPacketR::payload_block() const
+{
+ return this->_payload_block;
+}
+
+void
+QUICZeroRttPacketR::attach_payload(Ptr<IOBufferBlock> payload, bool unprotected)
+{
+ this->_payload_block = payload;
+}
+
+//
+// QUICHandshakePacket
+//
+QUICHandshakePacket::QUICHandshakePacket(QUICVersion version, QUICConnectionId dcid, QUICConnectionId scid, size_t length,
+ QUICPacketNumber packet_number, bool ack_eliciting, bool probing, bool crypto)
+ : QUICLongHeaderPacket(version, dcid, scid, ack_eliciting, probing, crypto), _packet_number(packet_number)
+{
+}
+
+QUICPacketType
+QUICHandshakePacket::type() const
+{
+ return QUICPacketType::HANDSHAKE;
+}
+
+QUICKeyPhase
+QUICHandshakePacket::key_phase() const
+{
+ return QUICKeyPhase::HANDSHAKE;
+}
+
+QUICPacketNumber
+QUICHandshakePacket::packet_number() const
+{
+ return this->_packet_number;
+}
+
+Ptr<IOBufferBlock>
+QUICHandshakePacket::header_block() const
+{
+ Ptr<IOBufferBlock> block;
+ size_t written_len = 0;
+ size_t n;
+
+ block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ block->alloc(iobuffer_size_to_index(2048, BUFFER_SIZE_INDEX_32K));
+ uint8_t *buf = reinterpret_cast<uint8_t *>(block->start());
+
+ // Common Long Header
+ written_len += this->_write_common_header(buf + written_len);
+
+ QUICPacketNumber pn = 0;
+ size_t pn_len = 4;
+ QUICPacket::encode_packet_number(pn, this->_packet_number, pn_len);
+
+ if (pn > 0x7FFFFF) {
+ pn_len = 4;
+ } else if (pn > 0x7FFF) {
+ pn_len = 3;
+ } else if (pn > 0x7F) {
+ pn_len = 2;
} else {
- dst = candidate2;
+ pn_len = 1;
}
- return true;
+ // PN Len
+ QUICTypeUtil::write_QUICPacketNumberLen(pn_len, buf);
+
+ // Length
+ QUICIntUtil::write_QUICVariableInt(pn_len + this->_payload_length, buf + written_len, &n);
+ written_len += n;
+
+ // PN Field
+ QUICTypeUtil::write_QUICPacketNumber(pn, pn_len, buf + written_len, &n);
+ written_len += n;
+
+ block->fill(written_len);
+
+ return block;
+}
+
+Ptr<IOBufferBlock>
+QUICHandshakePacket::payload_block() const
+{
+ return this->_payload_block;
+}
+
+void
+QUICHandshakePacket::attach_payload(Ptr<IOBufferBlock> payload, bool unprotected)
+{
+ this->_payload_block = payload;
+ this->_payload_length = 0;
+ Ptr<IOBufferBlock> tmp = payload;
+ while (tmp) {
+ this->_payload_length += tmp->size();
+ tmp = tmp->next;
+ }
+ if (unprotected) {
+ this->_payload_length += aead_tag_len;
+ }
+}
+
+//
+// QUICHandshakePacketR
+//
+QUICHandshakePacketR::QUICHandshakePacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks,
+ QUICPacketNumber base_packet_number)
+ : QUICLongHeaderPacketR(udp_con, from, to, blocks)
+{
+ size_t len = 0;
+ for (auto b = blocks; b; b = b->next) {
+ len += b->size();
+ }
+
+ Ptr<IOBufferBlock> concatinated_block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ concatinated_block->alloc(iobuffer_size_to_index(len, BUFFER_SIZE_INDEX_32K));
+ concatinated_block->fill(len);
+
+ uint8_t *raw_buf = reinterpret_cast<uint8_t *>(concatinated_block->start());
+
+ size_t copied_len = 0;
+ for (auto b = blocks; b; b = b->next) {
+ memcpy(raw_buf + copied_len, b->start(), b->size());
+ copied_len += b->size();
+ }
+
+ uint8_t dcil = 0;
+ uint8_t scil = 0;
+ QUICInvariants::dcil(dcil, raw_buf, len);
+ QUICInvariants::scil(scil, raw_buf, len);
+
+ size_t offset = LONG_HDR_OFFSET_CONNECTION_ID;
+ this->_dcid = {raw_buf + offset, dcil};
+ offset += dcil + 1;
+ this->_scid = {raw_buf + offset, scil};
+ offset += scil;
+
+ // Length Field
+ offset += QUICVariableInt::size(raw_buf + offset);
+
+ // PN Field
+ int pn_len = QUICTypeUtil::read_QUICPacketNumberLen(raw_buf);
+ QUICPacket::decode_packet_number(this->_packet_number, QUICTypeUtil::read_QUICPacketNumber(raw_buf + offset, pn_len), pn_len,
+ base_packet_number);
+ offset += pn_len;
+
+ this->_header_block = concatinated_block->clone();
+ this->_header_block->_end = this->_header_block->_start + offset;
+ this->_header_block->next = nullptr;
+ this->_payload_block = concatinated_block->clone();
+ this->_payload_block->_start = this->_payload_block->_start + offset;
+}
+
+QUICPacketType
+QUICHandshakePacketR::type() const
+{
+ return QUICPacketType::HANDSHAKE;
+}
+
+QUICKeyPhase
+QUICHandshakePacketR::key_phase() const
+{
+ return QUICKeyPhase::HANDSHAKE;
+}
+
+QUICPacketNumber
+QUICHandshakePacketR::packet_number() const
+{
+ return this->_packet_number;
+}
+
+Ptr<IOBufferBlock>
+QUICHandshakePacketR::header_block() const
+{
+ return this->_header_block;
+}
+
+Ptr<IOBufferBlock>
+QUICHandshakePacketR::payload_block() const
+{
+ return this->_payload_block;
+}
+
+void
+QUICHandshakePacketR::attach_payload(Ptr<IOBufferBlock> payload, bool unprotected)
+{
+ this->_payload_block = payload;
+}
+
+//
+// QUICRetryPacket
+//
+QUICRetryPacket::QUICRetryPacket(QUICVersion version, QUICConnectionId dcid, QUICConnectionId scid, QUICRetryToken &token)
+ : QUICLongHeaderPacket(version, dcid, scid, false, false, false), _token(token)
+{
+}
+
+QUICPacketType
+QUICRetryPacket::type() const
+{
+ return QUICPacketType::RETRY;
+}
+
+QUICPacketNumber
+QUICRetryPacket::packet_number() const
+{
+ ink_assert(!"You should not need packet number of Retry Packet");
+ return 0;
+}
+
+uint16_t
+QUICRetryPacket::payload_length() const
+{
+ uint16_t size = 0;
+
+ for (auto b = this->payload_block(); b; b = b->next) {
+ size += b->size();
+ }
+
+ return size;
+}
+
+Ptr<IOBufferBlock>
+QUICRetryPacket::header_block() const
+{
+ Ptr<IOBufferBlock> block;
+ size_t written_len = 0;
+
+ block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ block->alloc(iobuffer_size_to_index(2048, BUFFER_SIZE_INDEX_32K));
+ uint8_t *buf = reinterpret_cast<uint8_t *>(block->start());
+
+ // Common Long Header
+ written_len += this->_write_common_header(buf + written_len);
+
+ block->fill(written_len);
+
+ return block;
+}
+
+Ptr<IOBufferBlock>
+QUICRetryPacket::payload_block() const
+{
+ Ptr<IOBufferBlock> block;
+ uint8_t *buf;
+ size_t written_len = 0;
+
+ block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ block->alloc(iobuffer_size_to_index(QUICConnectionId::MAX_LENGTH + this->_token.length() + QUICRetryIntegrityTag::LEN,
+ BUFFER_SIZE_INDEX_32K));
+ buf = reinterpret_cast<uint8_t *>(block->start());
+
+ // Retry Token
+ memcpy(buf + written_len, this->_token.buf(), this->_token.length());
+ written_len += this->_token.length();
+ block->fill(written_len);
+
+ // Retry Integrity Tag
+ QUICRetryIntegrityTag::compute(buf + written_len, this->_token.original_dcid(), this->header_block(), block);
+ written_len += QUICRetryIntegrityTag::LEN;
+ block->fill(QUICRetryIntegrityTag::LEN);
+
+ return block;
+}
+
+const QUICRetryToken &
+QUICRetryPacket::token() const
+{
+ return this->_token;
+}
+
+//
+// QUICRetryPacketR
+//
+QUICRetryPacketR::QUICRetryPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks)
+ : QUICLongHeaderPacketR(udp_con, from, to, blocks)
+{
+ size_t len = 0;
+ for (auto b = blocks; b; b = b->next) {
+ len += b->size();
+ }
+
+ Ptr<IOBufferBlock> concatinated_block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ concatinated_block->alloc(iobuffer_size_to_index(len, BUFFER_SIZE_INDEX_32K));
+ concatinated_block->fill(len);
+
+ uint8_t *raw_buf = reinterpret_cast<uint8_t *>(concatinated_block->start());
+
+ size_t copied_len = 0;
+ for (auto b = blocks; b; b = b->next) {
+ memcpy(raw_buf + copied_len, b->start(), b->size());
+ copied_len += b->size();
+ }
+
+ uint8_t dcil = 0;
+ uint8_t scil = 0;
+ QUICInvariants::dcil(dcil, raw_buf, len);
+ QUICInvariants::scil(scil, raw_buf, len);
+
+ size_t offset = LONG_HDR_OFFSET_CONNECTION_ID;
+ this->_dcid = {raw_buf + offset, dcil};
+ offset += dcil + 1;
+ this->_scid = {raw_buf + offset, scil};
+ offset += scil;
+
+ // Retry Token field
+ this->_token = new QUICRetryToken(raw_buf + offset, len - offset - QUICRetryIntegrityTag::LEN);
+ offset += this->_token->length();
+
+ // Retry Integrity Tag
+ memcpy(this->_integrity_tag, raw_buf + offset, QUICRetryIntegrityTag::LEN);
+
+ this->_header_block = concatinated_block->clone();
+ this->_header_block->_end = this->_header_block->_start + offset;
+ this->_header_block->next = nullptr;
+ this->_payload_block = concatinated_block->clone();
+ this->_payload_block->_start = this->_payload_block->_start + offset;
+ this->_payload_block_without_tag = this->_payload_block->clone();
+ this->_payload_block_without_tag->_end = this->_payload_block_without_tag->_end - QUICRetryIntegrityTag::LEN;
+}
+
+QUICRetryPacketR::~QUICRetryPacketR()
+{
+ delete this->_token;
+}
+
+Ptr<IOBufferBlock>
+QUICRetryPacketR::header_block() const
+{
+ return this->_header_block;
+}
+
+Ptr<IOBufferBlock>
+QUICRetryPacketR::payload_block() const
+{
+ return this->_payload_block;
+}
+
+QUICPacketType
+QUICRetryPacketR::type() const
+{
+ return QUICPacketType::RETRY;
+}
+
+QUICPacketNumber
+QUICRetryPacketR::packet_number() const
+{
+ return 0;
+}
+
+const QUICAddressValidationToken &
+QUICRetryPacketR::token() const
+{
+ return *(this->_token);
+}
+
+bool
+QUICRetryPacketR::has_valid_tag(QUICConnectionId &odcid) const
+{
+ uint8_t tag_computed[QUICRetryIntegrityTag::LEN];
+ QUICRetryIntegrityTag::compute(tag_computed, 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 5fc834f..9d20b23 100644
--- a/iocore/net/quic/QUICPacket.h
+++ b/iocore/net/quic/QUICPacket.h
@@ -27,394 +27,524 @@
#include <atomic>
#include <cstddef>
-#include "tscore/List.h"
#include "I_IOBuffer.h"
#include "QUICTypes.h"
-#include "QUICHandshakeProtocol.h"
-#include "QUICPacketHeaderProtector.h"
-#include "QUICFrame.h"
+#include "QUICRetryIntegrityTag.h"
#define QUIC_FIELD_OFFSET_CONNECTION_ID 1
#define QUIC_FIELD_OFFSET_PACKET_NUMBER 4
#define QUIC_FIELD_OFFSET_PAYLOAD 5
class UDPConnection;
-class QUICPacketHeader;
-class QUICPacket;
-class QUICPacketLongHeader;
-class QUICPacketShortHeader;
-extern ClassAllocator<QUICPacket> quicPacketAllocator;
-extern ClassAllocator<QUICPacketLongHeader> quicPacketLongHeaderAllocator;
-extern ClassAllocator<QUICPacketShortHeader> quicPacketShortHeaderAllocator;
-
-using QUICPacketHeaderDeleterFunc = void (*)(QUICPacketHeader *p);
-using QUICPacketHeaderUPtr = std::unique_ptr<QUICPacketHeader, QUICPacketHeaderDeleterFunc>;
-
-class QUICPacketHeader
+class QUICPacket
{
public:
- QUICPacketHeader(const IpEndpoint from, const IpEndpoint to, ats_unique_buf buf, size_t len, QUICPacketNumber base)
- : _from(from), _to(to), _buf(std::move(buf)), _buf_len(len), _base_packet_number(base)
- {
- }
- ~QUICPacketHeader() {}
- const uint8_t *buf();
+ static constexpr int MAX_INSTANCE_SIZE = 1024;
- virtual bool is_crypto_packet() const;
+ // Token field in Initial packet could be very long.
+ static constexpr size_t MAX_PACKET_HEADER_LEN = 256;
- const IpEndpoint &from() const;
- const IpEndpoint &to() const;
+ /**
+ * Creates a QUICPacket for sending packets
+ */
+ QUICPacket(bool ack_eliciting, bool probing);
- virtual QUICPacketType type() const = 0;
+ virtual ~QUICPacket();
- /*
- * Returns a connection id
- */
+ virtual QUICPacketType type() const = 0;
virtual QUICConnectionId destination_cid() const = 0;
- virtual QUICConnectionId source_cid() const = 0;
+ virtual QUICPacketNumber packet_number() const = 0;
+ bool is_ack_eliciting() const;
+ bool is_probing_packet() const;
- virtual QUICPacketNumber packet_number() const = 0;
- virtual QUICVersion version() const = 0;
+ // TODO These two should be pure virtual
+ virtual Ptr<IOBufferBlock>
+ header_block() const
+ {
+ return Ptr<IOBufferBlock>();
+ };
+ virtual Ptr<IOBufferBlock>
+ payload_block() const
+ {
+ return Ptr<IOBufferBlock>();
+ };
/*
- * Returns a pointer for the payload
+ * Size of whole QUIC packet (header + payload + integrity check)
*/
- virtual const uint8_t *payload() const = 0;
+ virtual uint16_t size() const;
/*
- * Returns its payload size based on header length and buffer size that is specified to the constructo.
+ * Size of header
*/
- uint16_t payload_size() const;
+ virtual uint16_t header_size() const;
/*
- * Returns its header size
+ * Length of payload (payload + integrity check if exists)
*/
- virtual uint16_t size() const = 0;
+ virtual uint16_t payload_length() const;
- /*
- * Returns its packet size
+ /**
+ * Key phase
*/
- uint16_t packet_size() const;
+ virtual QUICKeyPhase key_phase() const;
- /*
- * Returns a key phase
- */
- virtual QUICKeyPhase key_phase() const = 0;
+ // FIXME Remove this and use IOBufferBlock instead
+ void store(uint8_t *buf, size_t *len) const;
- /*
- * Stores serialized header
- *
- * The serialized data doesn't contain a payload part even if it was created with a buffer that contains payload data.
- */
- virtual void store(uint8_t *buf, size_t *len) const = 0;
+ /***** STATIC MEMBERS *****/
- QUICPacketHeaderUPtr clone() const;
+ static uint8_t calc_packet_number_len(QUICPacketNumber num, QUICPacketNumber base);
+ static bool encode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len);
+ static bool decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len, QUICPacketNumber largest_acked);
- virtual bool has_version() const = 0;
- virtual bool is_valid() const = 0;
+protected:
+ QUICPacket();
- /***** STATIC members *****/
+private:
+ bool _is_ack_eliciting = false;
+ bool _is_probing_packet = false;
+};
- /*
- * Load data from a buffer and create a QUICPacketHeader
- *
- * This creates either a QUICPacketShortHeader or a QUICPacketLongHeader.
+class QUICPacketR : public QUICPacket
+{
+public:
+ /**
+ * Creates a QUICPacket for receiving packets
*/
- static QUICPacketHeaderUPtr load(const IpEndpoint from, const IpEndpoint to, ats_unique_buf buf, size_t len,
- QUICPacketNumber base);
+ QUICPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to);
- /*
- * Build a QUICPacketHeader
- *
- * This creates a QUICPacketLongHeader.
- */
- static QUICPacketHeaderUPtr build(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId destination_cid,
- QUICConnectionId source_cid, QUICPacketNumber packet_number,
- QUICPacketNumber base_packet_number, QUICVersion version, bool crypto, ats_unique_buf payload,
- size_t len);
+ virtual QUICPacketType type() const override = 0;
- /*
- * Build a QUICPacketHeader
- *
- * This creates a QUICPacketLongHeader for INITIAL packet
- */
- static QUICPacketHeaderUPtr build(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId destination_cid,
- QUICConnectionId source_cid, QUICPacketNumber packet_number,
- QUICPacketNumber base_packet_number, QUICVersion version, bool crypto, ats_unique_buf payload,
- size_t len, ats_unique_buf token, size_t token_len);
+ UDPConnection *udp_con() const;
+ virtual const IpEndpoint &from() const;
+ virtual const IpEndpoint &to() const;
- /*
- * Build a QUICPacketHeader
- *
- * This creates a QUICPacketLongHeader for RETRY packet
- */
- static QUICPacketHeaderUPtr build(QUICPacketType type, QUICKeyPhase key_phase, QUICVersion version,
- QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICConnectionId original_dcid,
- ats_unique_buf retry_token, size_t retry_token_len);
+ static bool read_essential_info(Ptr<IOBufferBlock> block, QUICPacketType &type, QUICVersion &version, QUICConnectionId &dcid,
+ QUICConnectionId &scid, QUICPacketNumber &packet_number, QUICPacketNumber base_packet_number,
+ QUICKeyPhase &key_phase);
+ static bool type(QUICPacketType &type, const uint8_t *packet, size_t packet_len);
- /*
- * Build a QUICPacketHeader
- *
- * This creates a QUICPacketShortHeader that contains a ConnectionID.
- */
- static QUICPacketHeaderUPtr build(QUICPacketType type, QUICKeyPhase key_phase, QUICPacketNumber packet_number,
- QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len);
+protected:
+ Ptr<IOBufferBlock> _header_block;
+ Ptr<IOBufferBlock> _payload_block;
- /*
- * Build a QUICPacketHeader
- *
- * This creates a QUICPacketShortHeader that doesn't contain a ConnectionID (Stateless Reset Packet).
+private:
+ UDPConnection *_udp_con = nullptr;
+ const IpEndpoint _from = {};
+ const IpEndpoint _to = {};
+};
+
+using QUICPacketDeleterFunc = void (*)(QUICPacket *p);
+using QUICPacketUPtr = std::unique_ptr<QUICPacket, QUICPacketDeleterFunc>;
+
+class QUICPacketDeleter
+{
+public:
+ static void
+ delete_null_packet(QUICPacket *packet)
+ {
+ ink_assert(packet == nullptr);
+ }
+
+ static void
+ delete_dont_free(QUICPacket *packet)
+ {
+ packet->~QUICPacket();
+ }
+
+ static void
+ delete_packet_new(QUICPacket *packet)
+ {
+ delete packet;
+ }
+};
+
+class QUICLongHeaderPacket : public QUICPacket
+{
+public:
+ /**
+ * For sending packet
*/
- static QUICPacketHeaderUPtr build(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId connection_id,
- QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf payload,
- size_t len);
+ QUICLongHeaderPacket(QUICVersion version, QUICConnectionId dcid, QUICConnectionId scid, bool ack_eliciting, bool probing,
+ bool crypto);
+
+ QUICConnectionId source_cid() const;
+
+ QUICConnectionId destination_cid() const override;
+ uint16_t payload_length() const override;
+ virtual QUICVersion version() const;
+ virtual bool is_crypto_packet() const;
protected:
- QUICPacketHeader(){};
- QUICPacketHeader(QUICPacketType type, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, bool has_version,
- QUICVersion version, ats_unique_buf payload, size_t payload_length, QUICKeyPhase key_phase)
- : _payload(std::move(payload)),
- _type(type),
- _key_phase(key_phase),
- _packet_number(packet_number),
- _base_packet_number(base_packet_number),
- _version(version),
- _payload_length(payload_length),
- _has_version(has_version){};
- // Token field in Initial packet could be very long.
- static constexpr size_t MAX_PACKET_HEADER_LEN = 256;
+ size_t _write_common_header(uint8_t *buf) const;
- const IpEndpoint _from = {};
- const IpEndpoint _to = {};
-
- // These two are used only if the instance was created with a buffer
- ats_unique_buf _buf = {nullptr};
- size_t _buf_len = 0;
-
- // These are used only if the instance was created without a buffer
- uint8_t _serialized[MAX_PACKET_HEADER_LEN];
- ats_unique_buf _payload = ats_unique_buf(nullptr);
- QUICPacketType _type = QUICPacketType::UNINITIALIZED;
- QUICKeyPhase _key_phase = QUICKeyPhase::INITIAL;
- QUICConnectionId _connection_id = QUICConnectionId::ZERO();
- QUICPacketNumber _packet_number = 0;
- QUICPacketNumber _base_packet_number = 0;
- QUICVersion _version = 0;
- size_t _payload_length = 0;
- bool _has_version = false;
+ Ptr<IOBufferBlock> _payload_block;
+ size_t _payload_length = 0;
+
+private:
+ QUICVersion _version;
+ QUICConnectionId _dcid;
+ QUICConnectionId _scid;
+
+ bool _is_crypto_packet;
};
-class QUICPacketLongHeader : public QUICPacketHeader
+class QUICLongHeaderPacketR : public QUICPacketR
{
public:
- QUICPacketLongHeader() : QUICPacketHeader(){};
- virtual ~QUICPacketLongHeader(){};
- QUICPacketLongHeader(const IpEndpoint from, const IpEndpoint to, ats_unique_buf buf, size_t len, QUICPacketNumber base);
- QUICPacketLongHeader(QUICPacketType type, QUICKeyPhase key_phase, const QUICConnectionId &destination_cid,
- const QUICConnectionId &source_cid, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number,
- QUICVersion version, bool crypto, ats_unique_buf buf, size_t len,
- ats_unique_buf token = ats_unique_buf(nullptr), size_t token_len = 0);
- QUICPacketLongHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICVersion version, const QUICConnectionId &destination_cid,
- const QUICConnectionId &source_cid, const QUICConnectionId &original_dcid, ats_unique_buf retry_token,
- size_t retry_token_len);
+ /**
+ * For receiving packet
+ */
+ QUICLongHeaderPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks);
+
+ virtual ~QUICLongHeaderPacketR(){};
- QUICPacketType type() const override;
QUICConnectionId destination_cid() const override;
- QUICConnectionId source_cid() const override;
- QUICConnectionId original_dcid() const;
- QUICPacketNumber packet_number() const override;
- bool has_version() const override;
- bool is_valid() const override;
- bool is_crypto_packet() const override;
- QUICVersion version() const override;
- const uint8_t *payload() const override;
- const uint8_t *token() const;
- size_t token_len() const;
- QUICKeyPhase key_phase() const override;
- uint16_t size() const override;
- void store(uint8_t *buf, size_t *len) const override;
+ QUICConnectionId source_cid() const;
+ virtual QUICVersion version() const;
static bool type(QUICPacketType &type, const uint8_t *packet, size_t packet_len);
static bool version(QUICVersion &version, const uint8_t *packet, size_t packet_len);
- static bool dcil(uint8_t &dcil, const uint8_t *packet, size_t packet_len);
- static bool scil(uint8_t &scil, const uint8_t *packet, size_t packet_len);
- static bool token_length(size_t &token_length, uint8_t &field_len, size_t &token_length_filed_offset, const uint8_t *packet,
- size_t packet_len);
+ static bool key_phase(QUICKeyPhase &key_phase, const uint8_t *packet, size_t packet_len);
static bool length(size_t &length, uint8_t &length_field_len, size_t &length_field_offset, const uint8_t *packet,
size_t packet_len);
- static bool key_phase(QUICKeyPhase &key_phase, const uint8_t *packet, size_t packet_len);
+ static bool packet_length(size_t &packet_len, const uint8_t *buf, size_t buf_len);
static bool packet_number_offset(size_t &pn_offset, const uint8_t *packet, size_t packet_len);
- static bool packet_length(size_t &length, const uint8_t *buf, size_t buf_len);
-private:
- QUICConnectionId _destination_cid = QUICConnectionId::ZERO();
- QUICConnectionId _source_cid = QUICConnectionId::ZERO();
- QUICConnectionId _original_dcid = QUICConnectionId::ZERO(); //< RETRY packet only
- size_t _token_len = 0; //< INITIAL packet only
- size_t _token_offset = 0; //< INITIAL packet only
- ats_unique_buf _token = ats_unique_buf(nullptr); //< INITIAL packet only
- size_t _payload_offset = 0;
- bool _is_crypto_packet = false;
+protected:
+ QUICVersion _version;
+ QUICConnectionId _scid;
+ QUICConnectionId _dcid;
};
-class QUICPacketShortHeader : public QUICPacketHeader
+class QUICShortHeaderPacket : public QUICPacket
{
public:
- QUICPacketShortHeader() : QUICPacketHeader(){};
- virtual ~QUICPacketShortHeader(){};
- QUICPacketShortHeader(const IpEndpoint from, const IpEndpoint to, ats_unique_buf buf, size_t len, QUICPacketNumber base);
- QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICPacketNumber packet_number,
- QUICPacketNumber base_packet_number, ats_unique_buf buf, size_t len);
- QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase key_phase, const QUICConnectionId &connection_id,
- QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf buf, size_t len);
+ /**
+ * For sending packet
+ */
+ QUICShortHeaderPacket(QUICConnectionId dcid, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number,
+ QUICKeyPhase key_phase, bool ack_eliciting, bool probing);
+
QUICPacketType type() const override;
- QUICConnectionId destination_cid() const override;
- QUICConnectionId
- source_cid() const override
- {
- return QUICConnectionId::ZERO();
- }
+ QUICKeyPhase key_phase() const override;
QUICPacketNumber packet_number() const override;
- bool has_version() const override;
- bool is_valid() const override;
- QUICVersion version() const override;
- const uint8_t *payload() const override;
+ QUICConnectionId destination_cid() const override;
+
+ uint16_t payload_length() const override;
+ Ptr<IOBufferBlock> header_block() const override;
+ Ptr<IOBufferBlock> payload_block() const override;
+
+ void attach_payload(Ptr<IOBufferBlock> payload, bool unprotected);
+
+private:
+ QUICConnectionId _dcid;
+ QUICPacketNumber _packet_number;
+ QUICKeyPhase _key_phase;
+ int _packet_number_len;
+
+ Ptr<IOBufferBlock> _payload_block;
+ size_t _payload_length;
+};
+
+class QUICShortHeaderPacketR : public QUICPacketR
+{
+public:
+ /**
+ * For receiving packet
+ */
+ QUICShortHeaderPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks,
+ QUICPacketNumber base_packet_number);
+
+ void attach_payload(Ptr<IOBufferBlock> payload, bool unprotected);
+
+ QUICPacketType type() const override;
QUICKeyPhase key_phase() const override;
- uint16_t size() const override;
- void store(uint8_t *buf, size_t *len) const override;
+ QUICPacketNumber packet_number() const override;
+ QUICConnectionId destination_cid() const override;
+
+ Ptr<IOBufferBlock> header_block() const override;
+ Ptr<IOBufferBlock> payload_block() const override;
- static bool key_phase(QUICKeyPhase &key_phase, const uint8_t *packet, size_t packet_len);
static bool packet_number_offset(size_t &pn_offset, const uint8_t *packet, size_t packet_len, int dcil);
private:
+ QUICKeyPhase _key_phase;
+ QUICPacketNumber _packet_number;
int _packet_number_len;
+ QUICConnectionId _dcid;
};
-class QUICPacketHeaderDeleter
+class QUICStatelessResetPacket : public QUICPacket
{
public:
- static void
- delete_null_header(QUICPacketHeader *header)
- {
- ink_assert(header == nullptr);
- }
+ /**
+ * For sending packet
+ */
+ QUICStatelessResetPacket(QUICStatelessResetToken token, size_t maximum_size);
- static void
- delete_long_header(QUICPacketHeader *header)
- {
- QUICPacketLongHeader *long_header = dynamic_cast<QUICPacketLongHeader *>(header);
- ink_assert(long_header != nullptr);
- long_header->~QUICPacketLongHeader();
- quicPacketLongHeaderAllocator.free(long_header);
- }
+ QUICPacketType type() const override;
+ QUICPacketNumber packet_number() const override;
+ QUICConnectionId destination_cid() const override;
- static void
- delete_short_header(QUICPacketHeader *header)
- {
- QUICPacketShortHeader *short_header = dynamic_cast<QUICPacketShortHeader *>(header);
- ink_assert(short_header != nullptr);
- short_header->~QUICPacketShortHeader();
- quicPacketShortHeaderAllocator.free(short_header);
- }
+ Ptr<IOBufferBlock> header_block() const override;
+ Ptr<IOBufferBlock> payload_block() const override;
+
+ QUICStatelessResetToken token() const;
+
+private:
+ QUICStatelessResetToken _token;
+ size_t _maximum_size;
};
-class QUICPacket
+class QUICStatelessResetPacketR : public QUICPacketR
{
public:
- QUICPacket();
+ /**
+ * For receiving packet
+ */
+ QUICStatelessResetPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks);
- /*
- * Creates a QUICPacket with a QUICPacketHeader and a buffer that contains payload
- *
- * This will be used for receiving packets. Therefore, it is expected that payload is already decrypted.
- * However, QUICPacket class itself doesn't care about whether the payload is protected (encrypted) or not.
+ QUICPacketType type() const override;
+ QUICPacketNumber packet_number() const override;
+ QUICConnectionId destination_cid() const override;
+};
+
+class QUICVersionNegotiationPacket : public QUICLongHeaderPacket
+{
+public:
+ /**
+ * For sending packet
*/
- QUICPacket(UDPConnection *udp_con, QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len);
+ QUICVersionNegotiationPacket(QUICConnectionId dcid, QUICConnectionId scid, const QUICVersion versions[], int nversions);
- QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, std::vector<QUICFrameInfo> &frames);
+ QUICPacketType type() const override;
+ QUICVersion version() const override;
+ QUICPacketNumber packet_number() const override;
+ uint16_t payload_length() const override;
- /*
- * Creates a QUICPacket with a QUICPacketHeader, a buffer that contains payload and a flag that indicates whether the packet is
- * ack_eliciting
- *
- * This will be used for sending packets. Therefore, it is expected that payload is already encrypted.
- * However, QUICPacket class itself doesn't care about whether the payload is protected (encrypted) or not.
+ Ptr<IOBufferBlock> header_block() const override;
+ Ptr<IOBufferBlock> payload_block() const override;
+
+ const QUICVersion *versions() const;
+ int nversions() const;
+
+private:
+ const QUICVersion *_versions;
+ int _nversions;
+};
+
+class QUICVersionNegotiationPacketR : public QUICLongHeaderPacketR
+{
+public:
+ /**
+ * For receiving packet
*/
- QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool ack_eliciting, bool probing);
+ QUICVersionNegotiationPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks);
- QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool ack_eliciting, bool probing,
- std::vector<QUICFrameInfo> &frames);
+ QUICPacketType type() const override;
+ QUICPacketNumber packet_number() const override;
+ QUICConnectionId destination_cid() const override;
- virtual ~QUICPacket();
+ Ptr<IOBufferBlock> header_block() const override;
+ Ptr<IOBufferBlock> payload_block() const override;
- UDPConnection *udp_con() const;
- virtual const IpEndpoint &from() const;
- virtual const IpEndpoint &to() const;
- QUICPacketType type() const;
- QUICConnectionId destination_cid() const;
- QUICConnectionId source_cid() const;
- QUICPacketNumber packet_number() const;
- QUICVersion version() const;
- const QUICPacketHeader &header() const;
- const uint8_t *payload() const;
- bool is_ack_eliciting() const;
- bool is_crypto_packet() const;
- bool is_probing_packet() const;
+ const QUICVersion supported_version(uint8_t index) const;
+ int nversions() const;
- /*
- * Size of whole QUIC packet (header + payload + integrity check)
+private:
+ QUICConnectionId _dcid;
+ uint8_t *_versions;
+ int _nversions;
+};
+
+class QUICInitialPacket : public QUICLongHeaderPacket
+{
+public:
+ /**
+ * For sending packet
*/
- uint16_t size() const;
+ QUICInitialPacket(QUICVersion version, QUICConnectionId dcid, QUICConnectionId scid, size_t token_len, ats_unique_buf token,
+ size_t length, QUICPacketNumber packet_number, bool ack_eliciting, bool probing, bool crypto);
- /*
- * Size of header
+ QUICPacketType type() const override;
+ QUICPacketNumber packet_number() const override;
+ QUICKeyPhase key_phase() const override;
+
+ Ptr<IOBufferBlock> header_block() const override;
+ Ptr<IOBufferBlock> payload_block() const override;
+ void attach_payload(Ptr<IOBufferBlock> payload, bool unprotected);
+
+private:
+ size_t _token_len = 0;
+ ats_unique_buf _token = ats_unique_buf(nullptr);
+ QUICPacketNumber _packet_number;
+};
+
+class QUICInitialPacketR : public QUICLongHeaderPacketR
+{
+public:
+ /**
+ * For receiving packet
*/
- uint16_t header_size() const;
+ QUICInitialPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks,
+ QUICPacketNumber base_packet_number);
+ ~QUICInitialPacketR();
- /*
- * Length of payload
+ Ptr<IOBufferBlock> header_block() const override;
+ Ptr<IOBufferBlock> payload_block() const override;
+ void attach_payload(Ptr<IOBufferBlock> payload, bool unprotected);
+
+ QUICPacketType type() const override;
+ QUICPacketNumber packet_number() const override;
+ QUICKeyPhase key_phase() const override;
+
+ const QUICAddressValidationToken &token() const;
+
+ static bool token_length(size_t &token_length, uint8_t &field_len, size_t &token_length_filed_offset, const uint8_t *packet,
+ size_t packet_len);
+
+protected:
+ Ptr<IOBufferBlock> _payload_block;
+
+private:
+ QUICPacketNumber _packet_number;
+ QUICAddressValidationToken *_token = nullptr;
+
+ bool _parse();
+};
+
+class QUICZeroRttPacket : public QUICLongHeaderPacket
+{
+public:
+ /**
+ * For sending packet
*/
- uint16_t payload_length() const;
+ QUICZeroRttPacket(QUICVersion version, QUICConnectionId dcid, QUICConnectionId scid, size_t length,
+ QUICPacketNumber packet_number, bool ack_eliciting, bool probing);
- void store(uint8_t *buf, size_t *len) const;
- QUICKeyPhase key_phase() const;
+ QUICPacketType type() const override;
+ QUICPacketNumber packet_number() const override;
+ QUICKeyPhase key_phase() const override;
- /***** STATIC MEMBERS *****/
+ Ptr<IOBufferBlock> header_block() const override;
+ Ptr<IOBufferBlock> payload_block() const override;
+ void attach_payload(Ptr<IOBufferBlock> payload, bool unprotected);
- static uint8_t calc_packet_number_len(QUICPacketNumber num, QUICPacketNumber base);
- static bool encode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len);
- static bool decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len, QUICPacketNumber largest_acked);
+private:
+ QUICPacketNumber _packet_number;
+};
+
+class QUICZeroRttPacketR : public QUICLongHeaderPacketR
+{
+public:
+ /**
+ * For receiving packet
+ */
+ QUICZeroRttPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks,
+ QUICPacketNumber base_packet_number);
- LINK(QUICPacket, link);
+ Ptr<IOBufferBlock> header_block() const override;
+ Ptr<IOBufferBlock> payload_block() const override;
+ void attach_payload(Ptr<IOBufferBlock> payload, bool unprotected);
+
+ QUICPacketType type() const override;
+ QUICPacketNumber packet_number() const override;
+ QUICKeyPhase key_phase() const override;
private:
- UDPConnection *_udp_con = nullptr;
- QUICPacketHeaderUPtr _header = QUICPacketHeaderUPtr(nullptr, &QUICPacketHeaderDeleter::delete_null_header);
- ats_unique_buf _payload = ats_unique_buf(nullptr);
- size_t _payload_size = 0;
- bool _is_ack_eliciting = false;
- bool _is_probing_packet = false;
+ QUICPacketNumber _packet_number;
};
-using QUICPacketDeleterFunc = void (*)(QUICPacket *p);
-using QUICPacketUPtr = std::unique_ptr<QUICPacket, QUICPacketDeleterFunc>;
+class QUICHandshakePacket : public QUICLongHeaderPacket
+{
+public:
+ /**
+ * For sending packet
+ */
+ QUICHandshakePacket(QUICVersion version, QUICConnectionId dcid, QUICConnectionId scid, size_t length,
+ QUICPacketNumber packet_number, bool ack_eliciting, bool probing, bool crypto);
-class QUICPacketDeleter
+ QUICPacketType type() const override;
+ QUICKeyPhase key_phase() const override;
+ QUICPacketNumber packet_number() const override;
+
+ Ptr<IOBufferBlock> header_block() const override;
+ Ptr<IOBufferBlock> payload_block() const override;
+ void attach_payload(Ptr<IOBufferBlock> payload, bool unprotected);
+
+private:
+ QUICPacketNumber _packet_number;
+};
+
+class QUICHandshakePacketR : public QUICLongHeaderPacketR
{
public:
- // TODO Probably these methods should call destructor
- static void
- delete_null_packet(QUICPacket *packet)
- {
- ink_assert(packet == nullptr);
- }
+ /**
+ * For receiving packet
+ */
+ QUICHandshakePacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks,
+ QUICPacketNumber base_packet_number);
- static void
- delete_packet(QUICPacket *packet)
- {
- packet->~QUICPacket();
- quicPacketAllocator.free(packet);
- }
+ Ptr<IOBufferBlock> header_block() const override;
+ Ptr<IOBufferBlock> payload_block() const override;
+ void attach_payload(Ptr<IOBufferBlock> payload, bool unprotected);
+
+ QUICPacketType type() const override;
+ QUICKeyPhase key_phase() const override;
+ QUICPacketNumber packet_number() const override;
+
+private:
+ QUICPacketNumber _packet_number;
+};
+
+class QUICRetryPacket : public QUICLongHeaderPacket
+{
+public:
+ /**
+ * For sending packet
+ */
+ QUICRetryPacket(QUICVersion version, QUICConnectionId dcid, QUICConnectionId scid, QUICRetryToken &token);
+
+ QUICPacketType type() const override;
+ QUICPacketNumber packet_number() const override;
+ uint16_t payload_length() const override;
+
+ Ptr<IOBufferBlock> header_block() const override;
+ Ptr<IOBufferBlock> payload_block() const override;
+
+ const QUICRetryToken &token() const;
+
+private:
+ QUICRetryToken _token;
+
+ bool _compute_retry_integrity_tag(uint8_t *out, QUICConnectionId odcid, Ptr<IOBufferBlock> header,
+ Ptr<IOBufferBlock> payload) const;
+};
+
+class QUICRetryPacketR : public QUICLongHeaderPacketR
+{
+public:
+ /**
+ * For receiving packet
+ */
+ QUICRetryPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks);
+ ~QUICRetryPacketR();
+
+ Ptr<IOBufferBlock> header_block() const override;
+ Ptr<IOBufferBlock> payload_block() const override;
+
+ QUICPacketType type() const override;
+ QUICPacketNumber packet_number() const override;
+
+ const QUICAddressValidationToken &token() const;
+ bool has_valid_tag(QUICConnectionId &odcid) const;
+
+private:
+ QUICAddressValidationToken *_token = nullptr;
+ uint8_t _integrity_tag[QUICRetryIntegrityTag::LEN];
+ Ptr<IOBufferBlock> _payload_block_without_tag;
};
diff --git a/iocore/net/quic/QUICPacketFactory.cc b/iocore/net/quic/QUICPacketFactory.cc
index ea82f44..436c683 100644
--- a/iocore/net/quic/QUICPacketFactory.cc
+++ b/iocore/net/quic/QUICPacketFactory.cc
@@ -62,282 +62,255 @@ QUICPacketFactory::create_null_packet()
}
QUICPacketUPtr
-QUICPacketFactory::create(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, ats_unique_buf buf, size_t len,
- QUICPacketNumber base_packet_number, QUICPacketCreationResult &result)
+QUICPacketFactory::create(uint8_t *packet_buf, UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, ats_unique_buf buf,
+ size_t len, QUICPacketNumber base_packet_number, QUICPacketCreationResult &result)
{
- size_t max_plain_txt_len = 2048;
- ats_unique_buf plain_txt = ats_unique_malloc(max_plain_txt_len);
- size_t plain_txt_len = 0;
-
- QUICPacketHeaderUPtr header = QUICPacketHeader::load(from, to, std::move(buf), len, base_packet_number);
-
- QUICConnectionId dcid = header->destination_cid();
- QUICConnectionId scid = header->source_cid();
- QUICVDebug(scid, dcid, "Decrypting %s packet #%" PRIu64 " using %s", QUICDebugNames::packet_type(header->type()),
- header->packet_number(), QUICDebugNames::key_phase(header->key_phase()));
-
- if (header->has_version() && !QUICTypeUtil::is_supported_version(header->version())) {
- if (header->type() == QUICPacketType::VERSION_NEGOTIATION) {
- // version of VN packet is 0x00000000
- // This packet is unprotected. Just copy the payload
- result = QUICPacketCreationResult::SUCCESS;
- memcpy(plain_txt.get(), header->payload(), header->payload_size());
- plain_txt_len = header->payload_size();
- } else {
- // We can't decrypt packets that have unknown versions
- // What we can use is invariant field of Long Header - version, dcid, and scid
- result = QUICPacketCreationResult::UNSUPPORTED;
- }
- } else {
- Ptr<IOBufferBlock> plain = make_ptr<IOBufferBlock>(new_IOBufferBlock());
- Ptr<IOBufferBlock> protected_ibb = make_ptr<IOBufferBlock>(new_IOBufferBlock());
- protected_ibb->set_internal(reinterpret_cast<void *>(const_cast<uint8_t *>(header->payload())), header->payload_size(),
- BUFFER_SIZE_NOT_ALLOCATED);
- Ptr<IOBufferBlock> header_ibb = make_ptr<IOBufferBlock>(new_IOBufferBlock());
- header_ibb->set_internal(reinterpret_cast<void *>(const_cast<uint8_t *>(header->buf())), header->size(),
- BUFFER_SIZE_NOT_ALLOCATED);
-
- switch (header->type()) {
- case QUICPacketType::STATELESS_RESET:
- case QUICPacketType::RETRY:
- // These packets are unprotected. Just copy the payload
- memcpy(plain_txt.get(), header->payload(), header->payload_size());
- plain_txt_len = header->payload_size();
- result = QUICPacketCreationResult::SUCCESS;
- break;
- case QUICPacketType::PROTECTED:
- if (this->_pp_key_info.is_decryption_key_available(header->key_phase())) {
- plain = this->_pp_protector.unprotect(header_ibb, protected_ibb, header->packet_number(), header->key_phase());
- if (plain != nullptr) {
- memcpy(plain_txt.get(), plain->buf(), plain->size());
- plain_txt_len = plain->size();
- result = QUICPacketCreationResult::SUCCESS;
- } else {
- result = QUICPacketCreationResult::FAILED;
- }
+ QUICPacket *packet = nullptr;
+
+ // FIXME This is temporal. Receive IOBufferBlock from the caller.
+ Ptr<IOBufferBlock> whole_data = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ whole_data->alloc(iobuffer_size_to_index(len, BUFFER_SIZE_INDEX_32K));
+ memcpy(whole_data->start(), buf.get(), len);
+ whole_data->fill(len);
+
+ QUICPacketType type;
+ QUICVersion version;
+ QUICConnectionId dcid;
+ QUICConnectionId scid;
+ QUICPacketNumber packet_number;
+ QUICKeyPhase key_phase;
+
+ if (QUICPacketR::read_essential_info(whole_data, type, version, dcid, scid, packet_number, base_packet_number, key_phase)) {
+ QUICVDebug(scid, dcid, "Decrypting %s packet #%" PRIu64 " using %s", QUICDebugNames::packet_type(type), packet_number,
+ QUICDebugNames::key_phase(key_phase));
+
+ if (type != QUICPacketType::PROTECTED && !QUICTypeUtil::is_supported_version(version)) {
+ if (type == QUICPacketType::VERSION_NEGOTIATION) {
+ packet = new QUICVersionNegotiationPacketR(udp_con, from, to, whole_data);
+ result = QUICPacketCreationResult::SUCCESS;
} else {
- result = QUICPacketCreationResult::NOT_READY;
+ // We can't decrypt packets that have unknown versions
+ // What we can use is invariant field of Long Header - version, dcid, and scid
+ result = QUICPacketCreationResult::UNSUPPORTED;
}
- break;
- case QUICPacketType::INITIAL:
- if (this->_pp_key_info.is_decryption_key_available(QUICKeyPhase::INITIAL)) {
- if (QUICTypeUtil::is_supported_version(header->version())) {
- plain = this->_pp_protector.unprotect(header_ibb, protected_ibb, header->packet_number(), header->key_phase());
+ } else {
+ Ptr<IOBufferBlock> plain;
+ switch (type) {
+ case QUICPacketType::STATELESS_RESET:
+ packet = new (packet_buf) QUICStatelessResetPacketR(udp_con, from, to, whole_data);
+ result = QUICPacketCreationResult::SUCCESS;
+ break;
+ case QUICPacketType::RETRY:
+ packet = new (packet_buf) QUICRetryPacketR(udp_con, from, to, whole_data);
+ result = QUICPacketCreationResult::SUCCESS;
+ break;
+ case QUICPacketType::PROTECTED:
+ packet = new (packet_buf) QUICShortHeaderPacketR(udp_con, from, to, whole_data, base_packet_number);
+ if (this->_pp_key_info.is_decryption_key_available(packet->key_phase())) {
+ plain = this->_pp_protector.unprotect(packet->header_block(), packet->payload_block(), packet->packet_number(),
+ packet->key_phase());
if (plain != nullptr) {
- memcpy(plain_txt.get(), plain->buf(), plain->size());
- plain_txt_len = plain->size();
- result = QUICPacketCreationResult::SUCCESS;
+ static_cast<QUICShortHeaderPacketR *>(packet)->attach_payload(plain, true);
+ result = QUICPacketCreationResult::SUCCESS;
} else {
result = QUICPacketCreationResult::FAILED;
}
} else {
- result = QUICPacketCreationResult::SUCCESS;
+ result = QUICPacketCreationResult::NOT_READY;
}
- } else {
- result = QUICPacketCreationResult::IGNORED;
- }
- break;
- case QUICPacketType::HANDSHAKE:
- if (this->_pp_key_info.is_decryption_key_available(QUICKeyPhase::HANDSHAKE)) {
- plain = this->_pp_protector.unprotect(header_ibb, protected_ibb, header->packet_number(), header->key_phase());
- if (plain != nullptr) {
- memcpy(plain_txt.get(), plain->buf(), plain->size());
- plain_txt_len = plain->size();
- result = QUICPacketCreationResult::SUCCESS;
+ break;
+ case QUICPacketType::INITIAL:
+ packet = new (packet_buf) QUICInitialPacketR(udp_con, from, to, whole_data, base_packet_number);
+ if (this->_pp_key_info.is_decryption_key_available(QUICKeyPhase::INITIAL)) {
+ plain = this->_pp_protector.unprotect(packet->header_block(), packet->payload_block(), packet->packet_number(),
+ packet->key_phase());
+ if (plain != nullptr) {
+ static_cast<QUICInitialPacketR *>(packet)->attach_payload(plain, true);
+ result = QUICPacketCreationResult::SUCCESS;
+ } else {
+ result = QUICPacketCreationResult::FAILED;
+ }
} else {
- result = QUICPacketCreationResult::FAILED;
+ result = QUICPacketCreationResult::IGNORED;
}
- } else {
- result = QUICPacketCreationResult::IGNORED;
- }
- break;
- case QUICPacketType::ZERO_RTT_PROTECTED:
- if (this->_pp_key_info.is_decryption_key_available(QUICKeyPhase::ZERO_RTT)) {
- plain = this->_pp_protector.unprotect(header_ibb, protected_ibb, header->packet_number(), header->key_phase());
- if (plain != nullptr) {
- memcpy(plain_txt.get(), plain->buf(), plain->size());
- plain_txt_len = plain->size();
- result = QUICPacketCreationResult::SUCCESS;
+ break;
+ case QUICPacketType::HANDSHAKE:
+ packet = new (packet_buf) QUICHandshakePacketR(udp_con, from, to, whole_data, base_packet_number);
+ if (this->_pp_key_info.is_decryption_key_available(QUICKeyPhase::HANDSHAKE)) {
+ plain = this->_pp_protector.unprotect(packet->header_block(), packet->payload_block(), packet->packet_number(),
+ packet->key_phase());
+ if (plain != nullptr) {
+ static_cast<QUICHandshakePacketR *>(packet)->attach_payload(plain, true);
+ result = QUICPacketCreationResult::SUCCESS;
+ } else {
+ result = QUICPacketCreationResult::FAILED;
+ }
} else {
result = QUICPacketCreationResult::IGNORED;
}
- } else {
- result = QUICPacketCreationResult::NOT_READY;
+ break;
+ case QUICPacketType::ZERO_RTT_PROTECTED:
+ packet = new (packet_buf) QUICZeroRttPacketR(udp_con, from, to, whole_data, base_packet_number);
+ if (this->_pp_key_info.is_decryption_key_available(QUICKeyPhase::ZERO_RTT)) {
+ plain = this->_pp_protector.unprotect(packet->header_block(), packet->payload_block(), packet->packet_number(),
+ packet->key_phase());
+ if (plain != nullptr) {
+ static_cast<QUICZeroRttPacketR *>(packet)->attach_payload(plain, true);
+ result = QUICPacketCreationResult::SUCCESS;
+ } else {
+ result = QUICPacketCreationResult::IGNORED;
+ }
+ } else {
+ result = QUICPacketCreationResult::NOT_READY;
+ }
+ break;
+ default:
+ result = QUICPacketCreationResult::FAILED;
+ break;
}
- break;
- default:
- result = QUICPacketCreationResult::FAILED;
- break;
}
+ } else {
+ Debug(tag.data(), "Failed to read essential field");
+ uint8_t *buf = reinterpret_cast<uint8_t *>(whole_data->start());
+ if (len > 16) {
+ Debug(tag_v.data(), "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", buf[0], buf[1], buf[2],
+ buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
+ }
+ if (len > 32) {
+ Debug(tag_v.data(), "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", buf[16 + 0],
+ buf[16 + 1], buf[16 + 2], buf[16 + 3], buf[16 + 4], buf[16 + 5], buf[16 + 6], buf[16 + 7], buf[16 + 8], buf[16 + 9],
+ buf[16 + 10], buf[16 + 11], buf[16 + 12], buf[16 + 13], buf[16 + 14], buf[16 + 15]);
+ }
+ if (len > 48) {
+ Debug(tag_v.data(), "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", buf[32 + 0],
+ buf[32 + 1], buf[32 + 2], buf[32 + 3], buf[32 + 4], buf[32 + 5], buf[32 + 6], buf[32 + 7], buf[32 + 8], buf[32 + 9],
+ buf[32 + 10], buf[32 + 11], buf[32 + 12], buf[32 + 13], buf[32 + 14], buf[32 + 15]);
+ }
+ result = QUICPacketCreationResult::FAILED;
}
- QUICPacket *packet = nullptr;
- if (result == QUICPacketCreationResult::SUCCESS || result == QUICPacketCreationResult::UNSUPPORTED) {
- packet = quicPacketAllocator.alloc();
- new (packet) QUICPacket(udp_con, std::move(header), std::move(plain_txt), plain_txt_len);
+ if (result != QUICPacketCreationResult::SUCCESS && result != QUICPacketCreationResult::UNSUPPORTED) {
+ packet = nullptr;
}
- return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet);
+ return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_dont_free);
}
QUICPacketUPtr
QUICPacketFactory::create_version_negotiation_packet(QUICConnectionId dcid, QUICConnectionId scid)
{
- size_t len = sizeof(QUICVersion) * (countof(QUIC_SUPPORTED_VERSIONS) + 1);
- ats_unique_buf versions(reinterpret_cast<uint8_t *>(ats_malloc(len)));
- uint8_t *p = versions.get();
-
- size_t n;
- for (auto v : QUIC_SUPPORTED_VERSIONS) {
- QUICTypeUtil::write_QUICVersion(v, p, &n);
- p += n;
- }
-
- // [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, p, &n);
- p += n;
-
- ink_assert(len == static_cast<size_t>(p - versions.get()));
- // VN packet dosen't have packet number field and version field is always 0x00000000
- QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::VERSION_NEGOTIATION, QUICKeyPhase::INITIAL, dcid, scid,
- 0x00, 0x00, 0x00, false, std::move(versions), len);
-
- return QUICPacketFactory::_create_unprotected_packet(std::move(header));
+ return QUICPacketUPtr(new QUICVersionNegotiationPacket(dcid, scid, QUIC_SUPPORTED_VERSIONS, countof(QUIC_SUPPORTED_VERSIONS)),
+ &QUICPacketDeleter::delete_packet_new);
}
QUICPacketUPtr
-QUICPacketFactory::create_initial_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid,
- QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len,
- bool retransmittable, bool probing, bool crypto, ats_unique_buf token, size_t token_len)
+QUICPacketFactory::create_initial_packet(uint8_t *packet_buf, QUICConnectionId destination_cid, QUICConnectionId source_cid,
+ QUICPacketNumber base_packet_number, Ptr<IOBufferBlock> payload, size_t length,
+ bool ack_eliciting, bool probing, bool crypto, ats_unique_buf token, size_t token_len)
{
QUICPacketNumberSpace index = QUICTypeUtil::pn_space(QUICEncryptionLevel::INITIAL);
QUICPacketNumber pn = this->_packet_number_generator[static_cast<int>(index)].next();
- QUICPacketHeaderUPtr header =
- QUICPacketHeader::build(QUICPacketType::INITIAL, QUICKeyPhase::INITIAL, destination_cid, source_cid, pn, base_packet_number,
- this->_version, crypto, std::move(payload), len, std::move(token), token_len);
- return this->_create_encrypted_packet(std::move(header), retransmittable, probing);
-}
-QUICPacketUPtr
-QUICPacketFactory::create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid,
- QUICConnectionId original_dcid, QUICRetryToken &token)
-{
- ats_unique_buf payload = ats_unique_malloc(token.length());
- memcpy(payload.get(), token.buf(), token.length());
+ QUICInitialPacket *packet = new (packet_buf) QUICInitialPacket(this->_version, destination_cid, source_cid, token_len,
+ std::move(token), length, pn, ack_eliciting, probing, crypto);
- QUICPacketHeaderUPtr header =
- QUICPacketHeader::build(QUICPacketType::RETRY, QUICKeyPhase::INITIAL, QUIC_SUPPORTED_VERSIONS[0], destination_cid, source_cid,
- original_dcid, std::move(payload), token.length());
- return QUICPacketFactory::_create_unprotected_packet(std::move(header));
-}
+ packet->attach_payload(payload, true); // Attach a cleartext payload with extra headers
+ Ptr<IOBufferBlock> protected_payload =
+ this->_pp_protector.protect(packet->header_block(), packet->payload_block(), packet->packet_number(), packet->key_phase());
+ if (protected_payload != nullptr) {
+ packet->attach_payload(protected_payload, false); // Replace its payload with the protected payload
+ } else {
+ QUICDebug(destination_cid, source_cid, "Failed to encrypt a packet");
+ packet = nullptr;
+ }
-QUICPacketUPtr
-QUICPacketFactory::create_handshake_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid,
- QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len,
- bool retransmittable, bool probing, bool crypto)
-{
- QUICPacketNumberSpace index = QUICTypeUtil::pn_space(QUICEncryptionLevel::HANDSHAKE);
- QUICPacketNumber pn = this->_packet_number_generator[static_cast<int>(index)].next();
- QUICPacketHeaderUPtr header =
- QUICPacketHeader::build(QUICPacketType::HANDSHAKE, QUICKeyPhase::HANDSHAKE, destination_cid, source_cid, pn, base_packet_number,
- this->_version, crypto, std::move(payload), len);
- return this->_create_encrypted_packet(std::move(header), retransmittable, probing);
+ return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_dont_free);
}
QUICPacketUPtr
-QUICPacketFactory::create_zero_rtt_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid,
- QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len,
- bool retransmittable, bool probing)
+QUICPacketFactory::create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICRetryToken &token)
{
- QUICPacketNumberSpace index = QUICTypeUtil::pn_space(QUICEncryptionLevel::ZERO_RTT);
- QUICPacketNumber pn = this->_packet_number_generator[static_cast<int>(index)].next();
- QUICPacketHeaderUPtr header =
- QUICPacketHeader::build(QUICPacketType::ZERO_RTT_PROTECTED, QUICKeyPhase::ZERO_RTT, destination_cid, source_cid, pn,
- base_packet_number, this->_version, false, std::move(payload), len);
- return this->_create_encrypted_packet(std::move(header), retransmittable, probing);
+ return QUICPacketUPtr(new QUICRetryPacket(QUIC_SUPPORTED_VERSIONS[0], destination_cid, source_cid, token),
+ &QUICPacketDeleter::delete_packet_new);
}
QUICPacketUPtr
-QUICPacketFactory::create_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number,
- ats_unique_buf payload, size_t len, bool retransmittable, bool probing)
+QUICPacketFactory::create_handshake_packet(uint8_t *packet_buf, QUICConnectionId destination_cid, QUICConnectionId source_cid,
+ QUICPacketNumber base_packet_number, Ptr<IOBufferBlock> payload, size_t length,
+ bool ack_eliciting, bool probing, bool crypto)
{
- QUICPacketNumberSpace index = QUICTypeUtil::pn_space(QUICEncryptionLevel::ONE_RTT);
+ QUICPacketNumberSpace index = QUICTypeUtil::pn_space(QUICEncryptionLevel::HANDSHAKE);
QUICPacketNumber pn = this->_packet_number_generator[static_cast<int>(index)].next();
- // TODO Key phase should be picked up from QUICHandshakeProtocol, probably
- QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::PROTECTED, QUICKeyPhase::PHASE_0, connection_id, pn,
- base_packet_number, std::move(payload), len);
- return this->_create_encrypted_packet(std::move(header), retransmittable, probing);
-}
-QUICPacketUPtr
-QUICPacketFactory::create_stateless_reset_packet(QUICConnectionId connection_id, QUICStatelessResetToken stateless_reset_token)
-{
- constexpr uint8_t MIN_UNPREDICTABLE_FIELD_LEN = 5;
- std::random_device rnd;
+ QUICHandshakePacket *packet =
+ new (packet_buf) QUICHandshakePacket(this->_version, destination_cid, source_cid, length, pn, ack_eliciting, probing, crypto);
- uint8_t random_packet_number = static_cast<uint8_t>(rnd() & 0xFF);
- size_t payload_len = static_cast<uint8_t>((rnd() & 0xFF) | (MIN_UNPREDICTABLE_FIELD_LEN + QUICStatelessResetToken::LEN));
- ats_unique_buf payload = ats_unique_malloc(payload_len);
- uint8_t *naked_payload = payload.get();
-
- // Generate random octets
- for (int i = payload_len - 1; i >= 0; --i) {
- naked_payload[i] = static_cast<uint8_t>(rnd() & 0xFF);
+ packet->attach_payload(payload, true); // Attach a cleartext payload with extra headers
+ Ptr<IOBufferBlock> protected_payload =
+ this->_pp_protector.protect(packet->header_block(), packet->payload_block(), packet->packet_number(), packet->key_phase());
+ if (protected_payload != nullptr) {
+ packet->attach_payload(protected_payload, false); // Replace its payload with the protected payload
+ } else {
+ QUICDebug(destination_cid, source_cid, "Failed to encrypt a packet");
+ packet = nullptr;
}
- // Copy stateless reset token into payload
- memcpy(naked_payload + payload_len - QUICStatelessResetToken::LEN, stateless_reset_token.buf(), QUICStatelessResetToken::LEN);
- // KeyPhase won't be used
- QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::STATELESS_RESET, QUICKeyPhase::INITIAL, connection_id,
- random_packet_number, 0, std::move(payload), payload_len);
- return QUICPacketFactory::_create_unprotected_packet(std::move(header));
+ return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_dont_free);
}
QUICPacketUPtr
-QUICPacketFactory::_create_unprotected_packet(QUICPacketHeaderUPtr header)
+QUICPacketFactory::create_zero_rtt_packet(uint8_t *packet_buf, QUICConnectionId destination_cid, QUICConnectionId source_cid,
+ QUICPacketNumber base_packet_number, Ptr<IOBufferBlock> payload, size_t length,
+ bool ack_eliciting, bool probing)
{
- ats_unique_buf cleartext = ats_unique_malloc(2048);
- size_t cleartext_len = header->payload_size();
+ QUICPacketNumberSpace index = QUICTypeUtil::pn_space(QUICEncryptionLevel::ZERO_RTT);
+ QUICPacketNumber pn = this->_packet_number_generator[static_cast<int>(index)].next();
+
+ QUICZeroRttPacket *packet =
+ new (packet_buf) QUICZeroRttPacket(this->_version, destination_cid, source_cid, length, pn, ack_eliciting, probing);
- memcpy(cleartext.get(), header->payload(), cleartext_len);
- QUICPacket *packet = quicPacketAllocator.alloc();
- new (packet) QUICPacket(std::move(header), std::move(cleartext), cleartext_len, false, false);
+ packet->attach_payload(payload, true); // Attach a cleartext payload with extra headers
+ Ptr<IOBufferBlock> protected_payload =
+ this->_pp_protector.protect(packet->header_block(), packet->payload_block(), packet->packet_number(), packet->key_phase());
+ if (protected_payload != nullptr) {
+ packet->attach_payload(protected_payload, false); // Replace its payload with the protected payload
+ } else {
+ QUICDebug(destination_cid, source_cid, "Failed to encrypt a packet");
+ packet = nullptr;
+ }
- return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet);
+ return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_dont_free);
}
QUICPacketUPtr
-QUICPacketFactory::_create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable, bool probing)
+QUICPacketFactory::create_short_header_packet(uint8_t *packet_buf, QUICConnectionId destination_cid,
+ QUICPacketNumber base_packet_number, Ptr<IOBufferBlock> payload, size_t length,
+ bool ack_eliciting, bool probing)
{
- QUICConnectionId dcid = header->destination_cid();
- QUICConnectionId scid = header->source_cid();
- QUICVDebug(dcid, scid, "Encrypting %s packet #%" PRIu64 " using %s", QUICDebugNames::packet_type(header->type()),
- header->packet_number(), QUICDebugNames::key_phase(header->key_phase()));
-
- QUICPacket *packet = nullptr;
-
- Ptr<IOBufferBlock> payload_ibb = make_ptr<IOBufferBlock>(new_IOBufferBlock());
- payload_ibb->set_internal(reinterpret_cast<void *>(const_cast<uint8_t *>(header->payload())), header->payload_size(),
- BUFFER_SIZE_NOT_ALLOCATED);
+ QUICPacketNumberSpace index = QUICTypeUtil::pn_space(QUICEncryptionLevel::ONE_RTT);
+ QUICPacketNumber pn = this->_packet_number_generator[static_cast<int>(index)].next();
- Ptr<IOBufferBlock> header_ibb = make_ptr<IOBufferBlock>(new_IOBufferBlock());
- header_ibb->set_internal(reinterpret_cast<void *>(const_cast<uint8_t *>(header->buf())), header->size(),
- BUFFER_SIZE_NOT_ALLOCATED);
+ // TODO Key phase should be picked up from QUICHandshakeProtocol, probably
+ QUICShortHeaderPacket *packet =
+ new (packet_buf) QUICShortHeaderPacket(destination_cid, pn, base_packet_number, QUICKeyPhase::PHASE_0, ack_eliciting, probing);
+ packet->attach_payload(payload, true); // Attach a cleartext payload with extra headers
Ptr<IOBufferBlock> protected_payload =
- this->_pp_protector.protect(header_ibb, payload_ibb, header->packet_number(), header->key_phase());
+ this->_pp_protector.protect(packet->header_block(), packet->payload_block(), packet->packet_number(), packet->key_phase());
if (protected_payload != nullptr) {
- ats_unique_buf cipher_txt = ats_unique_malloc(protected_payload->size());
- memcpy(cipher_txt.get(), protected_payload->buf(), protected_payload->size());
- packet = quicPacketAllocator.alloc();
- new (packet) QUICPacket(std::move(header), std::move(cipher_txt), protected_payload->size(), retransmittable, probing);
+ packet->attach_payload(protected_payload, false); // Replace its payload with the protected payload
} else {
- QUICDebug(dcid, scid, "Failed to encrypt a packet");
+ QUICDebug(destination_cid, QUICConnectionId::ZERO(), "Failed to encrypt a packet");
+ packet = nullptr;
}
- return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet);
+ return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_dont_free);
+}
+
+QUICPacketUPtr
+QUICPacketFactory::create_stateless_reset_packet(QUICStatelessResetToken stateless_reset_token, size_t maximum_size)
+{
+ return QUICPacketUPtr(new QUICStatelessResetPacket(stateless_reset_token, maximum_size), &QUICPacketDeleter::delete_packet_new);
}
void
diff --git a/iocore/net/quic/QUICPacketFactory.h b/iocore/net/quic/QUICPacketFactory.h
index 732ad35..d5316ce 100644
--- a/iocore/net/quic/QUICPacketFactory.h
+++ b/iocore/net/quic/QUICPacketFactory.h
@@ -45,27 +45,26 @@ class QUICPacketFactory
public:
static QUICPacketUPtr create_null_packet();
static QUICPacketUPtr create_version_negotiation_packet(QUICConnectionId dcid, QUICConnectionId scid);
- static QUICPacketUPtr create_stateless_reset_packet(QUICConnectionId connection_id,
- QUICStatelessResetToken stateless_reset_token);
- static QUICPacketUPtr create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid,
- QUICConnectionId original_dcid, QUICRetryToken &token);
+ 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);
QUICPacketFactory(const QUICPacketProtectionKeyInfo &pp_key_info) : _pp_key_info(pp_key_info), _pp_protector(pp_key_info) {}
- QUICPacketUPtr create(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, ats_unique_buf buf, size_t len,
+ QUICPacketUPtr create(uint8_t *packet_buf, UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, ats_unique_buf buf, size_t len,
QUICPacketNumber base_packet_number, QUICPacketCreationResult &result);
- QUICPacketUPtr create_initial_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid,
- QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool ack_eliciting,
- bool probing, bool crypto, ats_unique_buf token = ats_unique_buf(nullptr),
- size_t token_len = 0);
- QUICPacketUPtr create_handshake_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid,
- QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len,
+ QUICPacketUPtr create_initial_packet(uint8_t *packet_buf, QUICConnectionId destination_cid, QUICConnectionId source_cid,
+ QUICPacketNumber base_packet_number, Ptr<IOBufferBlock> payload, size_t length,
+ bool ack_eliciting, bool probing, bool crypto,
+ ats_unique_buf token = ats_unique_buf(nullptr), size_t token_len = 0);
+ QUICPacketUPtr create_handshake_packet(uint8_t *packet_buf, QUICConnectionId destination_cid, QUICConnectionId source_cid,
+ QUICPacketNumber base_packet_number, Ptr<IOBufferBlock> payload, size_t length,
bool ack_eliciting, bool probing, bool crypto);
- QUICPacketUPtr create_zero_rtt_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid,
- QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool ack_eliciting,
- bool probing);
- QUICPacketUPtr create_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number,
- ats_unique_buf payload, size_t len, bool ack_eliciting, bool probing);
+ QUICPacketUPtr create_zero_rtt_packet(uint8_t *packet_buf, QUICConnectionId destination_cid, QUICConnectionId source_cid,
+ QUICPacketNumber base_packet_number, Ptr<IOBufferBlock> payload, size_t length,
+ bool ack_eliciting, bool probing);
+ QUICPacketUPtr create_short_header_packet(uint8_t *packet_buf, QUICConnectionId destination_cid,
+ QUICPacketNumber base_packet_number, Ptr<IOBufferBlock> payload, size_t length,
+ bool ack_eliciting, bool probing);
void set_version(QUICVersion negotiated_version);
bool is_ready_to_create_protected_packet();
@@ -79,7 +78,4 @@ private:
// Initial, 0/1-RTT, and Handshake
QUICPacketNumberGenerator _packet_number_generator[3];
-
- static QUICPacketUPtr _create_unprotected_packet(QUICPacketHeaderUPtr header);
- QUICPacketUPtr _create_encrypted_packet(QUICPacketHeaderUPtr header, bool ack_eliciting, bool probing);
};
diff --git a/iocore/net/quic/QUICPacketHeaderProtector.cc b/iocore/net/quic/QUICPacketHeaderProtector.cc
index 0dbfe8d..f6a71b4 100644
--- a/iocore/net/quic/QUICPacketHeaderProtector.cc
+++ b/iocore/net/quic/QUICPacketHeaderProtector.cc
@@ -32,19 +32,15 @@ bool
QUICPacketHeaderProtector::protect(uint8_t *unprotected_packet, size_t unprotected_packet_len, int dcil) const
{
// Do nothing if the packet is VN
- if (QUICInvariants::is_long_header(unprotected_packet)) {
- QUICVersion version;
- QUICPacketLongHeader::version(version, unprotected_packet, unprotected_packet_len);
- if (version == 0x0) {
- return true;
- }
+ QUICPacketType type;
+ QUICPacketR::type(type, unprotected_packet, unprotected_packet_len);
+ if (type == QUICPacketType::VERSION_NEGOTIATION) {
+ return true;
}
QUICKeyPhase phase;
- QUICPacketType type;
if (QUICInvariants::is_long_header(unprotected_packet)) {
- QUICPacketLongHeader::key_phase(phase, unprotected_packet, unprotected_packet_len);
- QUICPacketLongHeader::type(type, unprotected_packet, unprotected_packet_len);
+ QUICLongHeaderPacketR::key_phase(phase, unprotected_packet, unprotected_packet_len);
} else {
// This is a kind of hack. For short header we need to use the same key for header protection regardless of the key phase.
phase = QUICKeyPhase::PHASE_0;
@@ -89,24 +85,15 @@ bool
QUICPacketHeaderProtector::unprotect(uint8_t *protected_packet, size_t protected_packet_len) const
{
// Do nothing if the packet is VN or RETRY
- if (QUICInvariants::is_long_header(protected_packet)) {
- QUICVersion version;
- QUICPacketLongHeader::version(version, protected_packet, protected_packet_len);
- if (version == 0x0) {
- return true;
- }
- QUICPacketType type;
- QUICPacketLongHeader::type(type, protected_packet, protected_packet_len);
- if (type == QUICPacketType::RETRY) {
- return true;
- }
+ QUICPacketType type;
+ QUICPacketR::type(type, protected_packet, protected_packet_len);
+ if (type == QUICPacketType::VERSION_NEGOTIATION || type == QUICPacketType::RETRY) {
+ return true;
}
QUICKeyPhase phase;
- QUICPacketType type;
if (QUICInvariants::is_long_header(protected_packet)) {
- QUICPacketLongHeader::key_phase(phase, protected_packet, protected_packet_len);
- QUICPacketLongHeader::type(type, protected_packet, protected_packet_len);
+ QUICLongHeaderPacketR::key_phase(phase, protected_packet, protected_packet_len);
} else {
// This is a kind of hack. For short header we need to use the same key for header protection regardless of the key phase.
phase = QUICKeyPhase::PHASE_0;
@@ -155,7 +142,7 @@ QUICPacketHeaderProtector::_calc_sample_offset(uint8_t *sample_offset, const uin
size_t dummy;
uint8_t length_len;
size_t length_offset;
- if (!QUICPacketLongHeader::length(dummy, length_len, length_offset, protected_packet, protected_packet_len)) {
+ if (!QUICLongHeaderPacketR::length(dummy, length_len, length_offset, protected_packet, protected_packet_len)) {
return false;
}
@@ -175,10 +162,10 @@ QUICPacketHeaderProtector::_unprotect(uint8_t *protected_packet, size_t protecte
// Unprotect packet number
if (QUICInvariants::is_long_header(protected_packet)) {
protected_packet[0] ^= mask[0] & 0x0f;
- QUICPacketLongHeader::packet_number_offset(pn_offset, protected_packet, protected_packet_len);
+ QUICLongHeaderPacketR::packet_number_offset(pn_offset, protected_packet, protected_packet_len);
} else {
protected_packet[0] ^= mask[0] & 0x1f;
- QUICPacketShortHeader::packet_number_offset(pn_offset, protected_packet, protected_packet_len, QUICConnectionId::SCID_LEN);
+ QUICShortHeaderPacketR::packet_number_offset(pn_offset, protected_packet, protected_packet_len, QUICConnectionId::SCID_LEN);
}
uint8_t pn_length = QUICTypeUtil::read_QUICPacketNumberLen(protected_packet);
@@ -199,10 +186,10 @@ QUICPacketHeaderProtector::_protect(uint8_t *protected_packet, size_t protected_
// Protect packet number
if (QUICInvariants::is_long_header(protected_packet)) {
protected_packet[0] ^= mask[0] & 0x0f;
- QUICPacketLongHeader::packet_number_offset(pn_offset, protected_packet, protected_packet_len);
+ QUICLongHeaderPacketR::packet_number_offset(pn_offset, protected_packet, protected_packet_len);
} else {
protected_packet[0] ^= mask[0] & 0x1f;
- QUICPacketShortHeader::packet_number_offset(pn_offset, protected_packet, protected_packet_len, dcil);
+ QUICShortHeaderPacketR::packet_number_offset(pn_offset, protected_packet, protected_packet_len, dcil);
}
for (int i = 0; i < pn_length; ++i) {
diff --git a/iocore/net/quic/QUICPacketHeaderProtector_boringssl.cc b/iocore/net/quic/QUICPacketHeaderProtector_boringssl.cc
index 54c539e..63e71bf 100644
--- a/iocore/net/quic/QUICPacketHeaderProtector_boringssl.cc
+++ b/iocore/net/quic/QUICPacketHeaderProtector_boringssl.cc
@@ -23,9 +23,36 @@
#include "QUICPacketHeaderProtector.h"
+#include "openssl/chacha.h"
+
bool
QUICPacketHeaderProtector::_generate_mask(uint8_t *mask, const uint8_t *sample, const uint8_t *key, const EVP_CIPHER *cipher) const
{
- ink_assert(!"not implemented");
- return false;
+ static constexpr unsigned char FIVE_ZEROS[] = {0x00, 0x00, 0x00, 0x00, 0x00};
+
+ if (cipher == nullptr) {
+ uint32_t counter = htole32(*reinterpret_cast<const uint32_t *>(&sample[0]));
+ CRYPTO_chacha_20(mask, FIVE_ZEROS, sizeof(FIVE_ZEROS), key, &sample[4], counter);
+ } else {
+ int len = 0;
+ EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+ if (!ctx) {
+ return false;
+ }
+ if (!EVP_EncryptInit_ex(ctx, cipher, nullptr, key, sample)) {
+ EVP_CIPHER_CTX_free(ctx);
+ return false;
+ }
+ if (!EVP_EncryptUpdate(ctx, mask, &len, sample, 16)) {
+ EVP_CIPHER_CTX_free(ctx);
+ return false;
+ }
+ if (!EVP_EncryptFinal_ex(ctx, mask + len, &len)) {
+ EVP_CIPHER_CTX_free(ctx);
+ return false;
+ }
+ EVP_CIPHER_CTX_free(ctx);
+ }
+
+ return true;
}
diff --git a/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc b/iocore/net/quic/QUICPacketHeaderProtector_legacy.cc
similarity index 100%
copy from iocore/net/quic/QUICPacketHeaderProtector_openssl.cc
copy to iocore/net/quic/QUICPacketHeaderProtector_legacy.cc
diff --git a/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc b/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc
index 43bbba8..c7d65a1 100644
--- a/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc
+++ b/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc
@@ -29,21 +29,28 @@ QUICPacketHeaderProtector::_generate_mask(uint8_t *mask, const uint8_t *sample,
static constexpr unsigned char FIVE_ZEROS[] = {0x00, 0x00, 0x00, 0x00, 0x00};
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
- if (!ctx || !EVP_EncryptInit_ex(ctx, cipher, nullptr, key, sample)) {
+ if (!ctx) {
+ return false;
+ }
+ if (!EVP_EncryptInit_ex(ctx, cipher, nullptr, key, sample)) {
+ EVP_CIPHER_CTX_free(ctx);
return false;
}
int len = 0;
if (cipher == EVP_chacha20()) {
if (!EVP_EncryptUpdate(ctx, mask, &len, FIVE_ZEROS, sizeof(FIVE_ZEROS))) {
+ EVP_CIPHER_CTX_free(ctx);
return false;
}
} else {
if (!EVP_EncryptUpdate(ctx, mask, &len, sample, 16)) {
+ EVP_CIPHER_CTX_free(ctx);
return false;
}
}
if (!EVP_EncryptFinal_ex(ctx, mask + len, &len)) {
+ EVP_CIPHER_CTX_free(ctx);
return false;
}
diff --git a/iocore/net/quic/QUICPacketPayloadProtector.cc b/iocore/net/quic/QUICPacketPayloadProtector.cc
index 374480b..4b8291c 100644
--- a/iocore/net/quic/QUICPacketPayloadProtector.cc
+++ b/iocore/net/quic/QUICPacketPayloadProtector.cc
@@ -46,12 +46,16 @@ QUICPacketPayloadProtector::protect(const Ptr<IOBufferBlock> unprotected_header,
const EVP_CIPHER *cipher = this->_pp_key_info.get_cipher(phase);
- protected_payload = make_ptr<IOBufferBlock>(new_IOBufferBlock());
- protected_payload->alloc(iobuffer_size_to_index(unprotected_payload->size() + tag_len, BUFFER_SIZE_INDEX_32K));
+ protected_payload = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ size_t unprotected_payload_len = 0;
+ for (Ptr<IOBufferBlock> tmp = unprotected_payload; tmp; tmp = tmp->next) {
+ unprotected_payload_len += tmp->size();
+ }
+ protected_payload->alloc(iobuffer_size_to_index(unprotected_payload_len + tag_len, BUFFER_SIZE_INDEX_32K));
size_t written_len = 0;
if (!this->_protect(reinterpret_cast<uint8_t *>(protected_payload->start()), written_len, protected_payload->write_avail(),
- unprotected_payload, pkt_num, reinterpret_cast<uint8_t *>(unprotected_header->buf()),
+ unprotected_payload, pkt_num, reinterpret_cast<uint8_t *>(unprotected_header->start()),
unprotected_header->size(), key, iv, iv_len, cipher, tag_len)) {
Debug(tag, "Failed to encrypt a packet #%" PRIu64 " with keys for %s", pkt_num, QUICDebugNames::key_phase(phase));
protected_payload = nullptr;
@@ -84,9 +88,9 @@ QUICPacketPayloadProtector::unprotect(const Ptr<IOBufferBlock> unprotected_heade
size_t written_len = 0;
if (!this->_unprotect(reinterpret_cast<uint8_t *>(unprotected_payload->start()), written_len, unprotected_payload->write_avail(),
- reinterpret_cast<uint8_t *>(protected_payload->buf()), protected_payload->size(), pkt_num,
- reinterpret_cast<uint8_t *>(unprotected_header->buf()), unprotected_header->size(), key, iv, iv_len, cipher,
- tag_len)) {
+ reinterpret_cast<uint8_t *>(protected_payload->start()), protected_payload->size(), pkt_num,
+ reinterpret_cast<uint8_t *>(unprotected_header->start()), unprotected_header->size(), key, iv, iv_len,
+ cipher, tag_len)) {
Debug(tag, "Failed to decrypt a packet #%" PRIu64, pkt_num);
unprotected_payload = nullptr;
} else {
@@ -122,3 +126,111 @@ QUICPacketPayloadProtector::_gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64
nonce[iv_len - 8 + i] ^= p[i];
}
}
+
+bool
+QUICPacketPayloadProtector::_protect(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const Ptr<IOBufferBlock> plain,
+ uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const uint8_t *key, const uint8_t *iv,
+ size_t iv_len, const EVP_CIPHER *aead, size_t tag_len) const
+{
+ EVP_CIPHER_CTX *aead_ctx;
+ int len;
+ uint8_t nonce[EVP_MAX_IV_LENGTH] = {0};
+ size_t nonce_len = 0;
+
+ this->_gen_nonce(nonce, nonce_len, pkt_num, iv, iv_len);
+
+ if (!(aead_ctx = EVP_CIPHER_CTX_new())) {
+ return false;
+ }
+ if (!EVP_EncryptInit_ex(aead_ctx, aead, nullptr, nullptr, nullptr)) {
+ return false;
+ }
+ if (!EVP_CIPHER_CTX_ctrl(aead_ctx, EVP_CTRL_AEAD_SET_IVLEN, nonce_len, nullptr)) {
+ return false;
+ }
+ if (!EVP_EncryptInit_ex(aead_ctx, nullptr, nullptr, key, nonce)) {
+ return false;
+ }
+ if (!EVP_EncryptUpdate(aead_ctx, nullptr, &len, ad, ad_len)) {
+ return false;
+ }
+
+ cipher_len = 0;
+ for (Ptr<IOBufferBlock> b = plain; b; b = b->next) {
+ if (!EVP_EncryptUpdate(aead_ctx, cipher + cipher_len, &len, reinterpret_cast<unsigned char *>(b->start()), b->size())) {
+ return false;
+ }
+ cipher_len += len;
+ }
+
+ if (!EVP_EncryptFinal_ex(aead_ctx, cipher + cipher_len, &len)) {
+ return false;
+ }
+ cipher_len += len;
+
+ if (max_cipher_len < cipher_len + tag_len) {
+ return false;
+ }
+ if (!EVP_CIPHER_CTX_ctrl(aead_ctx, EVP_CTRL_AEAD_GET_TAG, tag_len, cipher + cipher_len)) {
+ return false;
+ }
+ cipher_len += tag_len;
+
+ EVP_CIPHER_CTX_free(aead_ctx);
+
+ return true;
+}
+
+bool
+QUICPacketPayloadProtector::_unprotect(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const uint8_t *cipher,
+ size_t cipher_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const uint8_t *key,
+ const uint8_t *iv, size_t iv_len, const EVP_CIPHER *aead, size_t tag_len) const
+{
+ EVP_CIPHER_CTX *aead_ctx;
+ int len;
+ uint8_t nonce[EVP_MAX_IV_LENGTH] = {0};
+ size_t nonce_len = 0;
+
+ this->_gen_nonce(nonce, nonce_len, pkt_num, iv, iv_len);
+
+ if (!(aead_ctx = EVP_CIPHER_CTX_new())) {
+ return false;
+ }
+ if (!EVP_DecryptInit_ex(aead_ctx, aead, nullptr, nullptr, nullptr)) {
+ return false;
+ }
+ if (!EVP_CIPHER_CTX_ctrl(aead_ctx, EVP_CTRL_AEAD_SET_IVLEN, nonce_len, nullptr)) {
+ return false;
+ }
+ if (!EVP_DecryptInit_ex(aead_ctx, nullptr, nullptr, key, nonce)) {
+ return false;
+ }
+ if (!EVP_DecryptUpdate(aead_ctx, nullptr, &len, ad, ad_len)) {
+ return false;
+ }
+
+ if (cipher_len < tag_len) {
+ return false;
+ }
+ cipher_len -= tag_len;
+ if (!EVP_DecryptUpdate(aead_ctx, plain, &len, cipher, cipher_len)) {
+ return false;
+ }
+ plain_len = len;
+
+ if (!EVP_CIPHER_CTX_ctrl(aead_ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, const_cast<uint8_t *>(cipher + cipher_len))) {
+ return false;
+ }
+
+ int ret = EVP_DecryptFinal_ex(aead_ctx, plain + len, &len);
+
+ EVP_CIPHER_CTX_free(aead_ctx);
+
+ if (ret > 0) {
+ plain_len += len;
+ return true;
+ } else {
+ Debug(tag, "Failed to decrypt -- the first 4 bytes decrypted are %0x %0x %0x %0x", plain[0], plain[1], plain[2], plain[3]);
+ return false;
+ }
+}
diff --git a/iocore/net/quic/QUICPacketPayloadProtector_boringssl.cc b/iocore/net/quic/QUICPacketPayloadProtector_boringssl.cc
index 56e88dd..0352e51 100644
--- a/iocore/net/quic/QUICPacketPayloadProtector_boringssl.cc
+++ b/iocore/net/quic/QUICPacketPayloadProtector_boringssl.cc
@@ -25,24 +25,129 @@
#include "QUICPacketPayloadProtector.h"
#include "tscore/Diags.h"
-// static constexpr char tag[] = "quic_ppp";
+static constexpr char tag[] = "quic_ppp";
bool
-QUICPacketPayloadProtector::_protect(uint8_t *protected_payload, size_t &protected_payload_len, size_t max_protecgted_payload_len,
- const Ptr<IOBufferBlock> plain, uint64_t pkt_num, const uint8_t *ad, size_t ad_len,
- const uint8_t *key, const uint8_t *iv, size_t iv_len, const EVP_CIPHER *cipher,
- size_t tag_len) const
+QUICPacketPayloadProtector::_protect(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const Ptr<IOBufferBlock> plain,
+ uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const uint8_t *key, const uint8_t *iv,
+ size_t iv_len, const EVP_CIPHER *aead, size_t tag_len) const
{
- ink_assert(!"not implemented");
- return false;
+ EVP_CIPHER_CTX *aead_ctx;
+ int len;
+ uint8_t nonce[EVP_MAX_IV_LENGTH] = {0};
+ size_t nonce_len = 0;
+
+ this->_gen_nonce(nonce, nonce_len, pkt_num, iv, iv_len);
+
+ if (!(aead_ctx = EVP_CIPHER_CTX_new())) {
+ return false;
+ }
+ if (!EVP_EncryptInit_ex(aead_ctx, aead, nullptr, nullptr, nullptr)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
+ return false;
+ }
+ if (!EVP_CIPHER_CTX_ctrl(aead_ctx, EVP_CTRL_AEAD_SET_IVLEN, nonce_len, nullptr)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
+ return false;
+ }
+ if (!EVP_EncryptInit_ex(aead_ctx, nullptr, nullptr, key, nonce)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
+ return false;
+ }
+ if (!EVP_EncryptUpdate(aead_ctx, nullptr, &len, ad, ad_len)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
+ return false;
+ }
+
+ cipher_len = 0;
+ Ptr<IOBufferBlock> b = plain;
+ while (b) {
+ if (!EVP_EncryptUpdate(aead_ctx, cipher + cipher_len, &len, reinterpret_cast<unsigned char *>(b->buf()), b->size())) {
+ EVP_CIPHER_CTX_free(aead_ctx);
+ return false;
+ }
+ cipher_len += len;
+ b = b->next;
+ }
+
+ if (!EVP_EncryptFinal_ex(aead_ctx, cipher + cipher_len, &len)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
+ return false;
+ }
+ cipher_len += len;
+
+ if (max_cipher_len < cipher_len + tag_len) {
+ EVP_CIPHER_CTX_free(aead_ctx);
+ return false;
+ }
+ if (!EVP_CIPHER_CTX_ctrl(aead_ctx, EVP_CTRL_AEAD_GET_TAG, tag_len, cipher + cipher_len)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
+ return false;
+ }
+ cipher_len += tag_len;
+
+ EVP_CIPHER_CTX_free(aead_ctx);
+
+ return true;
}
bool
-QUICPacketPayloadProtector::_unprotect(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const uint8_t *protected_payload,
- size_t protected_payload_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len,
- const uint8_t *key, const uint8_t *iv, size_t iv_len, const EVP_CIPHER *cipher,
- size_t tag_len) const
+QUICPacketPayloadProtector::_unprotect(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const uint8_t *cipher,
+ size_t cipher_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const uint8_t *key,
+ const uint8_t *iv, size_t iv_len, const EVP_CIPHER *aead, size_t tag_len) const
{
- ink_assert(!"not implemented");
- return false;
+ EVP_CIPHER_CTX *aead_ctx;
+ int len;
+ uint8_t nonce[EVP_MAX_IV_LENGTH] = {0};
+ size_t nonce_len = 0;
+
+ this->_gen_nonce(nonce, nonce_len, pkt_num, iv, iv_len);
+
+ if (!(aead_ctx = EVP_CIPHER_CTX_new())) {
+ return false;
+ }
+ if (!EVP_DecryptInit_ex(aead_ctx, aead, nullptr, nullptr, nullptr)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
+ return false;
+ }
+ if (!EVP_CIPHER_CTX_ctrl(aead_ctx, EVP_CTRL_AEAD_SET_IVLEN, nonce_len, nullptr)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
+ return false;
+ }
+ if (!EVP_DecryptInit_ex(aead_ctx, nullptr, nullptr, key, nonce)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
+ return false;
+ }
+ if (!EVP_DecryptUpdate(aead_ctx, nullptr, &len, ad, ad_len)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
+ return false;
+ }
+
+ if (cipher_len < tag_len) {
+ EVP_CIPHER_CTX_free(aead_ctx);
+ return false;
+ }
+ cipher_len -= tag_len;
+ if (!EVP_DecryptUpdate(aead_ctx, plain, &len, cipher, cipher_len)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
+ return false;
+ }
+ plain_len = len;
+
+ if (!EVP_CIPHER_CTX_ctrl(aead_ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, const_cast<uint8_t *>(cipher + cipher_len))) {
+ EVP_CIPHER_CTX_free(aead_ctx);
+ return false;
+ }
+
+ int ret = EVP_DecryptFinal_ex(aead_ctx, plain + len, &len);
+
+ EVP_CIPHER_CTX_free(aead_ctx);
+
+ if (ret > 0) {
+ plain_len += len;
+ return true;
+ } else {
+ Debug(tag, "Failed to decrypt -- the first 4 bytes decrypted are %0x %0x %0x %0x", plain[0], plain[1], plain[2], plain[3]);
+ return false;
+ }
}
diff --git a/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc b/iocore/net/quic/QUICPacketPayloadProtector_legacy.cc
similarity index 96%
copy from iocore/net/quic/QUICPacketPayloadProtector_openssl.cc
copy to iocore/net/quic/QUICPacketPayloadProtector_legacy.cc
index b25f099..5fc9e2e 100644
--- a/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc
+++ b/iocore/net/quic/QUICPacketPayloadProtector_legacy.cc
@@ -55,14 +55,12 @@ QUICPacketPayloadProtector::_protect(uint8_t *cipher, size_t &cipher_len, size_t
return false;
}
- cipher_len = 0;
- Ptr<IOBufferBlock> b = plain;
- while (b) {
- if (!EVP_EncryptUpdate(aead_ctx, cipher + cipher_len, &len, reinterpret_cast<unsigned char *>(b->buf()), b->size())) {
+ cipher_len = 0;
+ for (Ptr<IOBufferBlock> b = plain; b; b = b->next) {
+ if (!EVP_EncryptUpdate(aead_ctx, cipher + cipher_len, &len, reinterpret_cast<unsigned char *>(b->start()), b->size())) {
return false;
}
cipher_len += len;
- b = b->next;
}
if (!EVP_EncryptFinal_ex(aead_ctx, cipher + cipher_len, &len)) {
diff --git a/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc b/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc
index b25f099..c900718 100644
--- a/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc
+++ b/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc
@@ -43,15 +43,19 @@ QUICPacketPayloadProtector::_protect(uint8_t *cipher, size_t &cipher_len, size_t
return false;
}
if (!EVP_EncryptInit_ex(aead_ctx, aead, nullptr, nullptr, nullptr)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
return false;
}
if (!EVP_CIPHER_CTX_ctrl(aead_ctx, EVP_CTRL_AEAD_SET_IVLEN, nonce_len, nullptr)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
return false;
}
if (!EVP_EncryptInit_ex(aead_ctx, nullptr, nullptr, key, nonce)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
return false;
}
if (!EVP_EncryptUpdate(aead_ctx, nullptr, &len, ad, ad_len)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
return false;
}
@@ -59,6 +63,7 @@ QUICPacketPayloadProtector::_protect(uint8_t *cipher, size_t &cipher_len, size_t
Ptr<IOBufferBlock> b = plain;
while (b) {
if (!EVP_EncryptUpdate(aead_ctx, cipher + cipher_len, &len, reinterpret_cast<unsigned char *>(b->buf()), b->size())) {
+ EVP_CIPHER_CTX_free(aead_ctx);
return false;
}
cipher_len += len;
@@ -66,14 +71,17 @@ QUICPacketPayloadProtector::_protect(uint8_t *cipher, size_t &cipher_len, size_t
}
if (!EVP_EncryptFinal_ex(aead_ctx, cipher + cipher_len, &len)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
return false;
}
cipher_len += len;
if (max_cipher_len < cipher_len + tag_len) {
+ EVP_CIPHER_CTX_free(aead_ctx);
return false;
}
if (!EVP_CIPHER_CTX_ctrl(aead_ctx, EVP_CTRL_AEAD_GET_TAG, tag_len, cipher + cipher_len)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
return false;
}
cipher_len += tag_len;
@@ -99,28 +107,35 @@ QUICPacketPayloadProtector::_unprotect(uint8_t *plain, size_t &plain_len, size_t
return false;
}
if (!EVP_DecryptInit_ex(aead_ctx, aead, nullptr, nullptr, nullptr)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
return false;
}
if (!EVP_CIPHER_CTX_ctrl(aead_ctx, EVP_CTRL_AEAD_SET_IVLEN, nonce_len, nullptr)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
return false;
}
if (!EVP_DecryptInit_ex(aead_ctx, nullptr, nullptr, key, nonce)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
return false;
}
if (!EVP_DecryptUpdate(aead_ctx, nullptr, &len, ad, ad_len)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
return false;
}
if (cipher_len < tag_len) {
+ EVP_CIPHER_CTX_free(aead_ctx);
return false;
}
cipher_len -= tag_len;
if (!EVP_DecryptUpdate(aead_ctx, plain, &len, cipher, cipher_len)) {
+ EVP_CIPHER_CTX_free(aead_ctx);
return false;
}
plain_len = len;
if (!EVP_CIPHER_CTX_ctrl(aead_ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, const_cast<uint8_t *>(cipher + cipher_len))) {
+ EVP_CIPHER_CTX_free(aead_ctx);
return false;
}
diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc
index c90385b..f197790 100644
--- a/iocore/net/quic/QUICPacketReceiveQueue.cc
+++ b/iocore/net/quic/QUICPacketReceiveQueue.cc
@@ -22,6 +22,7 @@
*/
#include "QUICPacketReceiveQueue.h"
+#include "QUICPacketHeaderProtector.h"
#include "QUICPacketFactory.h"
#include "QUICIntUtil.h"
@@ -44,7 +45,7 @@ QUICPacketReceiveQueue::enqueue(UDPPacket *packet)
}
QUICPacketUPtr
-QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result)
+QUICPacketReceiveQueue::dequeue(uint8_t *packet_buf, QUICPacketCreationResult &result)
{
QUICPacketUPtr quic_packet = QUICPacketFactory::create_null_packet();
UDPPacket *udp_packet = nullptr;
@@ -67,7 +68,7 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result)
IOBufferBlock *b = udp_packet->getIOBlockChain();
size_t written = 0;
while (b) {
- memcpy(this->_payload.get() + written, b->buf(), b->read_avail());
+ memcpy(this->_payload.get() + written, b->start(), b->read_avail());
written += b->read_avail();
b = b->next.get();
}
@@ -83,7 +84,7 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result)
if (QUICInvariants::is_long_header(buf)) {
QUICVersion version;
- QUICPacketLongHeader::version(version, buf, remaining_len);
+ QUICLongHeaderPacketR::version(version, buf, remaining_len);
if (is_vn(version)) {
pkt_len = remaining_len;
type = QUICPacketType::VERSION_NEGOTIATION;
@@ -91,17 +92,17 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result)
result = QUICPacketCreationResult::UNSUPPORTED;
pkt_len = remaining_len;
} else {
- QUICPacketLongHeader::type(type, this->_payload.get() + this->_offset, remaining_len);
+ QUICLongHeaderPacketR::type(type, this->_payload.get() + this->_offset, remaining_len);
if (type == QUICPacketType::RETRY) {
pkt_len = remaining_len;
} else {
- if (!QUICPacketLongHeader::packet_length(pkt_len, this->_payload.get() + this->_offset, remaining_len)) {
+ if (!QUICLongHeaderPacketR::packet_length(pkt_len, this->_payload.get() + this->_offset, remaining_len)) {
+ // This should not happen basically. Ignore rest of data on current packet.
this->_payload.release();
this->_payload = nullptr;
this->_payload_len = 0;
this->_offset = 0;
-
- result = QUICPacketCreationResult::IGNORED;
+ result = QUICPacketCreationResult::IGNORED;
return quic_packet;
}
@@ -148,7 +149,7 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result)
}
if (this->_ph_protector.unprotect(pkt.get(), pkt_len)) {
- quic_packet = this->_packet_factory.create(this->_udp_con, this->_from, this->_to, std::move(pkt), pkt_len,
+ quic_packet = this->_packet_factory.create(packet_buf, this->_udp_con, this->_from, this->_to, std::move(pkt), pkt_len,
this->_largest_received_packet_number, result);
} else {
// ZERO_RTT might be rejected
@@ -175,7 +176,8 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result)
// do nothing - if the packet is unsupported version, we don't know packet number
break;
default:
- if (quic_packet && quic_packet->packet_number() > this->_largest_received_packet_number) {
+ if (quic_packet && quic_packet->type() != QUICPacketType::VERSION_NEGOTIATION &&
+ quic_packet->packet_number() > this->_largest_received_packet_number) {
this->_largest_received_packet_number = quic_packet->packet_number();
}
}
diff --git a/iocore/net/quic/QUICPacketReceiveQueue.h b/iocore/net/quic/QUICPacketReceiveQueue.h
index e4e3e29..78e5b00 100644
--- a/iocore/net/quic/QUICPacketReceiveQueue.h
+++ b/iocore/net/quic/QUICPacketReceiveQueue.h
@@ -29,6 +29,7 @@
#include "QUICPacket.h"
class QUICPacketFactory;
+class QUICPacketHeaderProtector;
class QUICPacketReceiveQueue
{
@@ -36,7 +37,7 @@ public:
QUICPacketReceiveQueue(QUICPacketFactory &packet_factory, QUICPacketHeaderProtector &ph_protector);
void enqueue(UDPPacket *packet);
- QUICPacketUPtr dequeue(QUICPacketCreationResult &result);
+ QUICPacketUPtr dequeue(uint8_t *packet_buf, QUICPacketCreationResult &result);
uint32_t size();
void reset();
diff --git a/iocore/net/quic/QUICPathManager.cc b/iocore/net/quic/QUICPathManager.cc
index 613efec..c0adbde 100644
--- a/iocore/net/quic/QUICPathManager.cc
+++ b/iocore/net/quic/QUICPathManager.cc
@@ -28,7 +28,7 @@
#define QUICDebug(fmt, ...) Debug("quic_path", "[%s] " fmt, this->_cinfo.cids().data(), ##__VA_ARGS__)
void
-QUICPathManager::open_new_path(const QUICPath &path, ink_hrtime timeout_in)
+QUICPathManagerImpl::open_new_path(const QUICPath &path, ink_hrtime timeout_in)
{
if (this->_verify_timeout_at == 0) {
// Overwrite _previous_path only if _current_path is verified
@@ -41,14 +41,14 @@ QUICPathManager::open_new_path(const QUICPath &path, ink_hrtime timeout_in)
}
void
-QUICPathManager::set_trusted_path(const QUICPath &path)
+QUICPathManagerImpl::set_trusted_path(const QUICPath &path)
{
this->_current_path = path;
this->_previous_path = path;
}
void
-QUICPathManager::_check_verify_timeout()
+QUICPathManagerImpl::_check_verify_timeout()
{
if (this->_verify_timeout_at != 0) {
if (this->_path_validator.is_validated(this->_current_path)) {
@@ -66,14 +66,14 @@ QUICPathManager::_check_verify_timeout()
}
const QUICPath &
-QUICPathManager::get_current_path()
+QUICPathManagerImpl::get_current_path()
{
this->_check_verify_timeout();
return this->_current_path;
}
const QUICPath &
-QUICPathManager::get_verified_path()
+QUICPathManagerImpl::get_verified_path()
{
this->_check_verify_timeout();
if (this->_verify_timeout_at != 0) {
diff --git a/iocore/net/quic/QUICPathManager.h b/iocore/net/quic/QUICPathManager.h
index 9f9eb37..1d4542a 100644
--- a/iocore/net/quic/QUICPathManager.h
+++ b/iocore/net/quic/QUICPathManager.h
@@ -31,15 +31,25 @@ class QUICPathValidator;
class QUICPathManager
{
public:
- QUICPathManager(const QUICConnectionInfoProvider &info, QUICPathValidator &path_validator)
+ virtual ~QUICPathManager() {}
+ virtual const QUICPath &get_current_path() = 0;
+ virtual const QUICPath &get_verified_path() = 0;
+ virtual void open_new_path(const QUICPath &path, ink_hrtime timeout_in) = 0;
+ virtual void set_trusted_path(const QUICPath &path) = 0;
+};
+
+class QUICPathManagerImpl : public QUICPathManager
+{
+public:
+ QUICPathManagerImpl(const QUICConnectionInfoProvider &info, QUICPathValidator &path_validator)
: _cinfo(info), _path_validator(path_validator)
{
}
- const QUICPath &get_current_path();
- const QUICPath &get_verified_path();
- void open_new_path(const QUICPath &path, ink_hrtime timeout_in);
- void set_trusted_path(const QUICPath &path);
+ const QUICPath &get_current_path() override;
+ const QUICPath &get_verified_path() override;
+ void open_new_path(const QUICPath &path, ink_hrtime timeout_in) override;
+ void set_trusted_path(const QUICPath &path) override;
private:
const QUICConnectionInfoProvider &_cinfo;
diff --git a/iocore/net/quic/QUICPinger.cc b/iocore/net/quic/QUICPinger.cc
index 84454c8..2514c02 100644
--- a/iocore/net/quic/QUICPinger.cc
+++ b/iocore/net/quic/QUICPinger.cc
@@ -24,18 +24,20 @@
#include "QUICPinger.h"
void
-QUICPinger::request()
+QUICPinger::request(QUICEncryptionLevel level)
{
SCOPED_MUTEX_LOCK(lock, this->_mutex, this_ethread());
- ++this->_need_to_fire;
+ ink_assert(level != QUICEncryptionLevel::NONE);
+ ++this->_need_to_fire[static_cast<int>(level)];
}
void
-QUICPinger::cancel()
+QUICPinger::cancel(QUICEncryptionLevel level)
{
SCOPED_MUTEX_LOCK(lock, this->_mutex, this_ethread());
- if (this->_need_to_fire > 0) {
- --this->_need_to_fire;
+ ink_assert(level != QUICEncryptionLevel::NONE);
+ if (this->_need_to_fire[static_cast<int>(level)] > 0) {
+ --this->_need_to_fire[static_cast<int>(level)];
}
}
@@ -44,27 +46,25 @@ QUICPinger::_will_generate_frame(QUICEncryptionLevel level, size_t current_packe
{
SCOPED_MUTEX_LOCK(lock, this->_mutex, this_ethread());
- if (level != QUICEncryptionLevel::ONE_RTT) {
- return false;
- }
-
// PING Frame is meaningless for ack_eliciting packet. Cancel it.
if (ack_eliciting) {
this->_ack_eliciting_packet_out = true;
- this->cancel();
+ this->cancel(level);
return false;
}
- if (this->_ack_eliciting_packet_out == false && !ack_eliciting && current_packet_size > 0 && this->_need_to_fire == 0) {
+ ink_assert(level != QUICEncryptionLevel::NONE);
+ if (this->_ack_eliciting_packet_out == false && !ack_eliciting && current_packet_size > 0 &&
+ this->_need_to_fire[static_cast<int>(level)] == 0) {
// force to send an PING Frame
- this->request();
+ this->request(level);
}
// only update `_ack_eliciting_packet_out` when we has something to send.
if (current_packet_size) {
this->_ack_eliciting_packet_out = ack_eliciting;
}
- return this->_need_to_fire > 0;
+ return this->_need_to_fire[static_cast<int>(level)] > 0;
}
/**
@@ -77,10 +77,11 @@ QUICPinger::_generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t /*
SCOPED_MUTEX_LOCK(lock, this->_mutex, this_ethread());
QUICFrame *frame = nullptr;
- if (level == QUICEncryptionLevel::ONE_RTT && this->_need_to_fire > 0 && maximum_frame_size > 0) {
+ ink_assert(level != QUICEncryptionLevel::NONE);
+ if (this->_need_to_fire[static_cast<int>(level)] > 0 && maximum_frame_size > 0) {
// don't care ping frame lost or acked
frame = QUICFrameFactory::create_ping_frame(buf, 0, nullptr);
- --this->_need_to_fire;
+ --this->_need_to_fire[static_cast<int>(level)];
this->_ack_eliciting_packet_out = true;
}
@@ -88,8 +89,9 @@ QUICPinger::_generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t /*
}
uint64_t
-QUICPinger::count()
+QUICPinger::count(QUICEncryptionLevel level)
{
SCOPED_MUTEX_LOCK(lock, this->_mutex, this_ethread());
- return this->_need_to_fire;
+ ink_assert(level != QUICEncryptionLevel::NONE);
+ return this->_need_to_fire[static_cast<int>(level)];
}
diff --git a/iocore/net/quic/QUICPinger.h b/iocore/net/quic/QUICPinger.h
index 483cfb2..0ea9b58 100644
--- a/iocore/net/quic/QUICPinger.h
+++ b/iocore/net/quic/QUICPinger.h
@@ -35,9 +35,9 @@ class QUICPinger : public QUICFrameOnceGenerator
public:
QUICPinger() : _mutex(new_ProxyMutex()) {}
- void request();
- void cancel();
- uint64_t count();
+ void request(QUICEncryptionLevel level);
+ void cancel(QUICEncryptionLevel level);
+ uint64_t count(QUICEncryptionLevel level);
private:
// QUICFrameGenerator
@@ -48,5 +48,5 @@ private:
bool _ack_eliciting_packet_out = false;
Ptr<ProxyMutex> _mutex;
- uint64_t _need_to_fire = 0;
+ uint64_t _need_to_fire[4] = {0}; // Initial, 0RTT, HANDSHAKE and 1RTT
};
diff --git a/iocore/net/quic/QUICResetTokenTable.cc b/iocore/net/quic/QUICResetTokenTable.cc
new file mode 100644
index 0000000..0da753f
--- /dev/null
+++ b/iocore/net/quic/QUICResetTokenTable.cc
@@ -0,0 +1,53 @@
+/** @file
+
+ @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.
+ */
+
+#include "tscore/Diags.h"
+#include "QUICResetTokenTable.h"
+#include "QUICConnection.h"
+
+void
+QUICResetTokenTable::insert(const QUICStatelessResetToken token, QUICConnection *connection)
+{
+ Debug("quic_reset_token_table", "Token:%02x%02x%02x%02x... CID:%08" PRIx32 "...", token.buf()[0], token.buf()[1], token.buf()[2],
+ token.buf()[3], connection->connection_id().h32());
+ this->_map.emplace(token, connection);
+}
+
+QUICConnection *
+QUICResetTokenTable::lookup(QUICStatelessResetToken token)
+{
+ Debug("quic_reset_token_table", "Token:%02x%02x%02x%02x...", token.buf()[0], token.buf()[1], token.buf()[2], token.buf()[3]);
+ auto result = this->_map.find(token);
+ if (result != this->_map.end()) {
+ Debug("quic_reset_token_table", "CID:%08" PRIx32 "...", result->second->connection_id().h32());
+ return result->second;
+ } else {
+ Debug("quic_reset_token_table", "not fouund");
+ return nullptr;
+ }
+}
+
+void
+QUICResetTokenTable::erase(const QUICStatelessResetToken token)
+{
+ Debug("quic_reset_token_table", "Token:%02x%02x%02x%02x...", token.buf()[0], token.buf()[1], token.buf()[2], token.buf()[3]);
+ this->_map.erase(token);
+}
diff --git a/proxy/http3/Http3StreamDataVIOAdaptor.h b/iocore/net/quic/QUICResetTokenTable.h
similarity index 62%
copy from proxy/http3/Http3StreamDataVIOAdaptor.h
copy to iocore/net/quic/QUICResetTokenTable.h
index f62fd31..559b264 100644
--- a/proxy/http3/Http3StreamDataVIOAdaptor.h
+++ b/iocore/net/quic/QUICResetTokenTable.h
@@ -1,7 +1,5 @@
/** @file
- A brief file description
-
@section license License
Licensed to the Apache Software Foundation (ASF) under one
@@ -23,19 +21,26 @@
#pragma once
-#include "Http3FrameHandler.h"
+#include "QUICTypes.h"
-class VIO;
+class QUICConnection;
-class Http3StreamDataVIOAdaptor : public Http3FrameHandler
+class QUICResetTokenTable
{
public:
- Http3StreamDataVIOAdaptor(VIO *sink);
-
- // Http3FrameHandler
- std::vector<Http3FrameType> interests() override;
- Http3ErrorUPtr handle_frame(std::shared_ptr<const Http3Frame> frame) override;
+ void insert(const QUICStatelessResetToken token, QUICConnection *connection);
+ QUICConnection *lookup(const QUICStatelessResetToken token);
+ void erase(const QUICStatelessResetToken token);
private:
- VIO *_sink_vio = nullptr;
+ class TokenHasher
+ {
+ public:
+ uint64_t
+ operator()(const QUICStatelessResetToken &key) const
+ {
+ return static_cast<uint64_t>(key);
+ }
+ };
+ std::unordered_map<QUICStatelessResetToken, QUICConnection *, TokenHasher> _map;
};
diff --git a/iocore/net/quic/QUICRetryIntegrityTag.cc b/iocore/net/quic/QUICRetryIntegrityTag.cc
new file mode 100644
index 0000000..c528656
--- /dev/null
+++ b/iocore/net/quic/QUICRetryIntegrityTag.cc
@@ -0,0 +1,79 @@
+/** @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.
+ */
+
+#include "QUICRetryIntegrityTag.h"
+
+bool
+QUICRetryIntegrityTag::compute(uint8_t *out, QUICConnectionId odcid, Ptr<IOBufferBlock> header, Ptr<IOBufferBlock> payload)
+{
+ EVP_CIPHER_CTX *aead_ctx;
+
+ if (!(aead_ctx = EVP_CIPHER_CTX_new())) {
+ return false;
+ }
+ if (!EVP_EncryptInit_ex(aead_ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr)) {
+ return false;
+ }
+ 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)) {
+ return false;
+ }
+
+ // Original Destination Connection ID
+ size_t n;
+ int dummy;
+ uint8_t odcid_buf[1 + QUICConnectionId::MAX_LENGTH];
+ // Len
+ odcid_buf[0] = odcid.length();
+ // ID
+ QUICTypeUtil::write_QUICConnectionId(odcid, odcid_buf + 1, &n);
+ if (!EVP_EncryptUpdate(aead_ctx, nullptr, &dummy, odcid_buf, 1 + odcid.length())) {
+ return false;
+ }
+
+ // Retry Packet
+ for (Ptr<IOBufferBlock> b = header; b; b = b->next) {
+ if (!EVP_EncryptUpdate(aead_ctx, nullptr, &dummy, reinterpret_cast<unsigned char *>(b->start()), b->size())) {
+ return false;
+ }
+ }
+ for (Ptr<IOBufferBlock> b = payload; b; b = b->next) {
+ if (!EVP_EncryptUpdate(aead_ctx, nullptr, &dummy, reinterpret_cast<unsigned char *>(b->start()), b->size())) {
+ return false;
+ }
+ }
+
+ if (!EVP_EncryptFinal_ex(aead_ctx, nullptr, &dummy)) {
+ return false;
+ }
+
+ if (!EVP_CIPHER_CTX_ctrl(aead_ctx, EVP_CTRL_AEAD_GET_TAG, LEN, out)) {
+ return false;
+ }
+
+ EVP_CIPHER_CTX_free(aead_ctx);
+
+ return true;
+}
diff --git a/iocore/net/quic/QUICIntUtil.h b/iocore/net/quic/QUICRetryIntegrityTag.h
similarity index 59%
copy from iocore/net/quic/QUICIntUtil.h
copy to iocore/net/quic/QUICRetryIntegrityTag.h
index c259bca..3ac9498 100644
--- a/iocore/net/quic/QUICIntUtil.h
+++ b/iocore/net/quic/QUICRetryIntegrityTag.h
@@ -23,23 +23,17 @@
#pragma once
-#include <cstddef>
-#include <cstdint>
+#include "QUICTypes.h"
-class QUICVariableInt
+class QUICRetryIntegrityTag
{
public:
- static size_t size(const uint8_t *src);
- static size_t size(uint64_t src);
- static int encode(uint8_t *dst, size_t dst_len, size_t &len, uint64_t src);
- static int decode(uint64_t &dst, size_t &len, const uint8_t *src, size_t src_len = 8);
-};
+ static constexpr int LEN = 16;
+ static bool compute(uint8_t *out, QUICConnectionId odcid, Ptr<IOBufferBlock> header, Ptr<IOBufferBlock> payload);
-class QUICIntUtil
-{
-public:
- static uint64_t read_QUICVariableInt(const uint8_t *buf);
- static void write_QUICVariableInt(uint64_t data, uint8_t *buf, size_t *len);
- static uint64_t read_nbytes_as_uint(const uint8_t *buf, uint8_t n);
- static void write_uint_as_nbytes(uint64_t value, uint8_t n, uint8_t *buf, size_t *len);
+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};
};
diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc
index 334b9f4..93ac8f1 100644
--- a/iocore/net/quic/QUICStream.cc
+++ b/iocore/net/quic/QUICStream.cc
@@ -245,7 +245,7 @@ QUICStreamVConnection::_signal_read_event()
}
MUTEX_TRY_LOCK(lock, this->_read_vio.mutex, this_ethread());
- int event = this->_read_vio.ntodo() ? VC_EVENT_READ_READY : VC_EVENT_READ_COMPLETE;
+ int event = this->_read_vio.nbytes == INT64_MAX ? VC_EVENT_READ_READY : VC_EVENT_READ_COMPLETE;
if (lock.is_locked()) {
this->_read_vio.cont->handleEvent(event, &this->_read_vio);
diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc
index de4ffb9..da66d74 100644
--- a/iocore/net/quic/QUICStreamManager.cc
+++ b/iocore/net/quic/QUICStreamManager.cc
@@ -29,10 +29,10 @@
static constexpr char tag[] = "quic_stream_manager";
static constexpr QUICStreamId QUIC_STREAM_TYPES = 4;
-QUICStreamManager::QUICStreamManager(QUICConnectionInfoProvider *info, QUICRTTProvider *rtt_provider, QUICApplicationMap *app_map)
- : _stream_factory(rtt_provider, info), _info(info), _app_map(app_map)
+QUICStreamManager::QUICStreamManager(QUICContext *context, QUICApplicationMap *app_map)
+ : _stream_factory(context->rtt_provider(), context->connection_info()), _context(context), _app_map(app_map)
{
- if (this->_info->direction() == NET_VCONNECTION_OUT) {
+ if (this->_context->connection_info()->direction() == NET_VCONNECTION_OUT) {
this->_next_stream_id_bidi = static_cast<uint32_t>(QUICStreamType::CLIENT_BIDI);
this->_next_stream_id_uni = static_cast<uint32_t>(QUICStreamType::CLIENT_UNI);
} else {
@@ -265,12 +265,13 @@ QUICStreamManager::_find_or_create_stream_vc(QUICStreamId stream_id)
uint64_t local_max_stream_data = 0;
uint64_t remote_max_stream_data = 0;
+ uint64_t nth_stream = this->_stream_id_to_nth_stream(stream_id);
switch (QUICTypeUtil::detect_stream_type(stream_id)) {
case QUICStreamType::CLIENT_BIDI:
- if (this->_info->direction() == NET_VCONNECTION_OUT) {
+ if (this->_context->connection_info()->direction() == NET_VCONNECTION_OUT) {
// client
- if (this->_remote_max_streams_bidi == 0 || stream_id > this->_remote_max_streams_bidi) {
+ if (this->_remote_max_streams_bidi == 0 || nth_stream > this->_remote_max_streams_bidi) {
return nullptr;
}
@@ -278,7 +279,7 @@ QUICStreamManager::_find_or_create_stream_vc(QUICStreamId stream_id)
remote_max_stream_data = this->_remote_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE);
} else {
// server
- if (this->_local_max_streams_bidi == 0 || stream_id > this->_local_max_streams_bidi) {
+ if (this->_local_max_streams_bidi == 0 || nth_stream > this->_local_max_streams_bidi) {
return nullptr;
}
@@ -288,14 +289,14 @@ QUICStreamManager::_find_or_create_stream_vc(QUICStreamId stream_id)
break;
case QUICStreamType::CLIENT_UNI:
- if (this->_info->direction() == NET_VCONNECTION_OUT) {
+ if (this->_context->connection_info()->direction() == NET_VCONNECTION_OUT) {
// client
- if (this->_remote_max_streams_uni == 0 || stream_id > this->_remote_max_streams_uni) {
+ if (this->_remote_max_streams_uni == 0 || nth_stream > this->_remote_max_streams_uni) {
return nullptr;
}
} else {
// server
- if (this->_local_max_streams_uni == 0 || stream_id > this->_local_max_streams_uni) {
+ if (this->_local_max_streams_uni == 0 || nth_stream > this->_local_max_streams_uni) {
return nullptr;
}
}
@@ -305,9 +306,9 @@ QUICStreamManager::_find_or_create_stream_vc(QUICStreamId stream_id)
break;
case QUICStreamType::SERVER_BIDI:
- if (this->_info->direction() == NET_VCONNECTION_OUT) {
+ if (this->_context->connection_info()->direction() == NET_VCONNECTION_OUT) {
// client
- if (this->_local_max_streams_bidi == 0 || stream_id > this->_local_max_streams_bidi) {
+ if (this->_local_max_streams_bidi == 0 || nth_stream > this->_local_max_streams_bidi) {
return nullptr;
}
@@ -315,7 +316,7 @@ QUICStreamManager::_find_or_create_stream_vc(QUICStreamId stream_id)
remote_max_stream_data = this->_remote_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL);
} else {
// server
- if (this->_remote_max_streams_bidi == 0 || stream_id > this->_remote_max_streams_bidi) {
+ if (this->_remote_max_streams_bidi == 0 || nth_stream > this->_remote_max_streams_bidi) {
return nullptr;
}
@@ -324,12 +325,12 @@ QUICStreamManager::_find_or_create_stream_vc(QUICStreamId stream_id)
}
break;
case QUICStreamType::SERVER_UNI:
- if (this->_info->direction() == NET_VCONNECTION_OUT) {
- if (this->_local_max_streams_uni == 0 || stream_id > this->_local_max_streams_uni) {
+ if (this->_context->connection_info()->direction() == NET_VCONNECTION_OUT) {
+ if (this->_local_max_streams_uni == 0 || nth_stream > this->_local_max_streams_uni) {
return nullptr;
}
} else {
- if (this->_remote_max_streams_uni == 0 || stream_id > this->_remote_max_streams_uni) {
+ if (this->_remote_max_streams_uni == 0 || nth_stream > this->_remote_max_streams_uni) {
return nullptr;
}
}
@@ -416,6 +417,11 @@ QUICStreamManager::will_generate_frame(QUICEncryptionLevel level, size_t current
return false;
}
+ // Don't send DATA frames if current path is not validated
+ if (!this->_context->path_manager()->get_verified_path().remote_ep().isValid()) {
+ return false;
+ }
+
for (QUICStreamVConnection *s = this->stream_list.head; s; s = s->link.next) {
if (s->will_generate_frame(level, current_packet_size, ack_eliciting, seq_num)) {
return true;
@@ -466,3 +472,9 @@ QUICStreamManager::_is_level_matched(QUICEncryptionLevel level)
return false;
}
+
+uint64_t
+QUICStreamManager::_stream_id_to_nth_stream(QUICStreamId stream_id)
+{
+ return (stream_id / 4) + 1;
+}
diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h
index fb38ecc..05da5fc 100644
--- a/iocore/net/quic/QUICStreamManager.h
+++ b/iocore/net/quic/QUICStreamManager.h
@@ -31,13 +31,15 @@
#include "QUICFrame.h"
#include "QUICStreamFactory.h"
#include "QUICLossDetector.h"
+#include "QUICPathManager.h"
+#include "QUICContext.h"
class QUICTransportParameters;
class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator
{
public:
- QUICStreamManager(QUICConnectionInfoProvider *info, QUICRTTProvider *rtt_provider, QUICApplicationMap *app_map);
+ QUICStreamManager(QUICContext *context, QUICApplicationMap *app_map);
void init_flow_control_params(const std::shared_ptr<const QUICTransportParameters> &local_tp,
const std::shared_ptr<const QUICTransportParameters> &remote_tp);
@@ -82,7 +84,7 @@ private:
QUICStreamFactory _stream_factory;
- QUICConnectionInfoProvider *_info = nullptr;
+ QUICContext *_context = nullptr;
QUICApplicationMap *_app_map = nullptr;
std::shared_ptr<const QUICTransportParameters> _local_tp = nullptr;
std::shared_ptr<const QUICTransportParameters> _remote_tp = nullptr;
@@ -97,4 +99,6 @@ private:
QUICEncryptionLevel::ZERO_RTT,
QUICEncryptionLevel::ONE_RTT,
};
+
+ uint64_t _stream_id_to_nth_stream(QUICStreamId stream_id);
};
diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc
index 5736ef4..b0317f2 100644
--- a/iocore/net/quic/QUICTLS.cc
+++ b/iocore/net/quic/QUICTLS.cc
@@ -32,6 +32,55 @@
constexpr static char tag[] = "quic_tls";
+static const char *
+content_type_str(int type)
+{
+ switch (type) {
+ case SSL3_RT_CHANGE_CIPHER_SPEC:
+ return "CHANGE_CIPHER_SPEC";
+ case SSL3_RT_ALERT:
+ return "ALERT";
+ case SSL3_RT_HANDSHAKE:
+ return "HANDSHAKE";
+ case SSL3_RT_APPLICATION_DATA:
+ return "APPLICATION_DATA";
+ case SSL3_RT_HEADER:
+ // The buf contains the record header bytes only
+ return "HEADER";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static const char *
+hs_type_str(int type)
+{
+ switch (type) {
+ case SSL3_MT_CLIENT_HELLO:
+ return "CLIENT_HELLO";
+ case SSL3_MT_SERVER_HELLO:
+ return "SERVER_HELLO";
+ case SSL3_MT_NEWSESSION_TICKET:
+ return "NEWSESSION_TICKET";
+ case SSL3_MT_END_OF_EARLY_DATA:
+ return "END_OF_EARLY_DATA";
+ case SSL3_MT_ENCRYPTED_EXTENSIONS:
+ return "ENCRYPTED_EXTENSIONS";
+ case SSL3_MT_CERTIFICATE:
+ return "CERTIFICATE";
+ case SSL3_MT_CERTIFICATE_VERIFY:
+ return "CERTIFICATE_VERIFY";
+ case SSL3_MT_FINISHED:
+ return "FINISHED";
+ case SSL3_MT_KEY_UPDATE:
+ return "KEY_UPDATE";
+ case SSL3_MT_MESSAGE_HASH:
+ return "MESSAGE_HASH";
+ default:
+ return "UNKNOWN";
+ }
+}
+
SSL *
QUICTLS::ssl_handle()
{
@@ -51,12 +100,6 @@ QUICTLS::remote_transport_parameters()
}
void
-QUICTLS::set_local_transport_parameters(std::shared_ptr<const QUICTransportParameters> tp)
-{
- this->_local_transport_parameters = tp;
-}
-
-void
QUICTLS::set_remote_transport_parameters(std::shared_ptr<const QUICTransportParameters> tp)
{
this->_remote_transport_parameters = tp;
@@ -79,16 +122,30 @@ QUICTLS::~QUICTLS()
SSL_free(this->_ssl);
}
+int
+QUICTLS::handshake(QUICHandshakeMsgs **out, const QUICHandshakeMsgs *in)
+{
+ if (this->is_handshake_finished()) {
+ if (in != nullptr && in->offsets[4] != 0) {
+ return this->_process_post_handshake_messages(*out, in);
+ }
+
+ return 0;
+ }
+
+ return this->_handshake(out, in);
+}
+
void
QUICTLS::reset()
{
SSL_clear(this->_ssl);
}
-uint16_t
+uint64_t
QUICTLS::convert_to_quic_trans_error_code(uint8_t alert)
{
- return 0x100 | alert;
+ return static_cast<uint64_t>(QUICTransErrorCode::CRYPTO_ERROR) + alert;
}
bool
@@ -114,7 +171,9 @@ QUICTLS::initialize_key_materials(QUICConnectionId cid)
this->_pp_key_info.set_cipher_for_hp_initial(EVP_aes_128_ecb());
// Generate keys
- Debug(tag, "Generating %s keys", QUICDebugNames::key_phase(QUICKeyPhase::INITIAL));
+ if (is_debug_tag_set(tag)) {
+ Debug(tag, "Generating %s keys with cid %s", QUICDebugNames::key_phase(QUICKeyPhase::INITIAL), cid.hex().c_str());
+ }
uint8_t *client_key_for_hp;
uint8_t *client_key;
@@ -172,6 +231,127 @@ QUICTLS::initialize_key_materials(QUICConnectionId cid)
return 1;
}
+void
+QUICTLS::update_negotiated_cipher()
+{
+ this->_store_negotiated_cipher();
+ this->_store_negotiated_cipher_for_hp();
+}
+
+void
+QUICTLS::update_key_materials_for_read(QUICEncryptionLevel level, const uint8_t *secret, size_t secret_len)
+{
+ if (this->_state == HandshakeState::ABORTED) {
+ return;
+ }
+
+ QUICKeyPhase phase;
+ const EVP_CIPHER *cipher;
+
+ switch (level) {
+ case QUICEncryptionLevel::ZERO_RTT:
+ phase = QUICKeyPhase::ZERO_RTT;
+ cipher = this->_pp_key_info.get_cipher(phase);
+ break;
+ case QUICEncryptionLevel::HANDSHAKE:
+ this->_update_encryption_level(QUICEncryptionLevel::HANDSHAKE);
+ phase = QUICKeyPhase::HANDSHAKE;
+ break;
+ case QUICEncryptionLevel::ONE_RTT:
+ this->_update_encryption_level(QUICEncryptionLevel::ONE_RTT);
+ // TODO Support Key Update
+ phase = QUICKeyPhase::PHASE_0;
+ break;
+ default:
+ phase = QUICKeyPhase::INITIAL;
+ break;
+ }
+
+ QUICHKDF hkdf(this->_get_handshake_digest());
+
+ uint8_t *key_for_hp;
+ uint8_t *key;
+ uint8_t *iv;
+ size_t key_for_hp_len;
+ size_t key_len;
+ size_t *iv_len;
+
+ cipher = this->_pp_key_info.get_cipher(phase);
+ key_for_hp = this->_pp_key_info.decryption_key_for_hp(phase);
+ key_for_hp_len = this->_pp_key_info.decryption_key_for_hp_len(phase);
+ key = this->_pp_key_info.decryption_key(phase);
+ key_len = this->_pp_key_info.decryption_key_len(phase);
+ iv = this->_pp_key_info.decryption_iv(phase);
+ iv_len = this->_pp_key_info.decryption_iv_len(phase);
+
+ if (this->_netvc_context == NET_VCONNECTION_IN) {
+ this->_keygen_for_client.regenerate(key_for_hp, key, iv, iv_len, secret, secret_len, cipher, hkdf);
+ this->_print_km("update - client", key_for_hp, key_for_hp_len, key, key_len, iv, *iv_len, secret, secret_len, phase);
+ } else {
+ this->_keygen_for_server.regenerate(key_for_hp, key, iv, iv_len, secret, secret_len, cipher, hkdf);
+ this->_print_km("update - server", key_for_hp, key_for_hp_len, key, key_len, iv, *iv_len, secret, secret_len, phase);
+ }
+
+ this->_pp_key_info.set_decryption_key_available(phase);
+}
+
+void
+QUICTLS::update_key_materials_for_write(QUICEncryptionLevel level, const uint8_t *secret, size_t secret_len)
+{
+ if (this->_state == HandshakeState::ABORTED) {
+ return;
+ }
+
+ QUICKeyPhase phase;
+ const EVP_CIPHER *cipher = nullptr;
+
+ switch (level) {
+ case QUICEncryptionLevel::ZERO_RTT:
+ phase = QUICKeyPhase::ZERO_RTT;
+ cipher = this->_pp_key_info.get_cipher(phase);
+ break;
+ case QUICEncryptionLevel::HANDSHAKE:
+ this->_update_encryption_level(QUICEncryptionLevel::HANDSHAKE);
+ phase = QUICKeyPhase::HANDSHAKE;
+ cipher = this->_pp_key_info.get_cipher(phase);
+ break;
+ case QUICEncryptionLevel::ONE_RTT:
+ this->_update_encryption_level(QUICEncryptionLevel::ONE_RTT);
+ phase = QUICKeyPhase::PHASE_0;
+ cipher = this->_pp_key_info.get_cipher(phase);
+ break;
+ default:
+ phase = QUICKeyPhase::INITIAL;
+ break;
+ }
+
+ QUICHKDF hkdf(this->_get_handshake_digest());
+
+ uint8_t *key_for_hp;
+ uint8_t *key;
+ uint8_t *iv;
+ size_t key_for_hp_len;
+ size_t key_len;
+ size_t *iv_len;
+
+ key_for_hp = this->_pp_key_info.encryption_key_for_hp(phase);
+ key_for_hp_len = this->_pp_key_info.encryption_key_for_hp_len(phase);
+ key = this->_pp_key_info.encryption_key(phase);
+ key_len = this->_pp_key_info.encryption_key_len(phase);
+ iv = this->_pp_key_info.encryption_iv(phase);
+ iv_len = this->_pp_key_info.encryption_iv_len(phase);
+
+ if (this->_netvc_context == NET_VCONNECTION_IN) {
+ this->_keygen_for_server.regenerate(key_for_hp, key, iv, iv_len, secret, secret_len, cipher, hkdf);
+ this->_print_km("update - server", key_for_hp, key_for_hp_len, key, key_len, iv, *iv_len, secret, secret_len, phase);
+ } else {
+ this->_keygen_for_client.regenerate(key_for_hp, key, iv, iv_len, secret, secret_len, cipher, hkdf);
+ this->_print_km("update - client", key_for_hp, key_for_hp_len, key, key_len, iv, *iv_len, secret, secret_len, phase);
+ }
+
+ this->_pp_key_info.set_encryption_key_available(phase);
+}
+
const char *
QUICTLS::negotiated_cipher_suite() const
{
@@ -199,6 +379,118 @@ QUICTLS::abort_handshake()
}
void
+QUICTLS::set_ready_for_write()
+{
+ this->_should_flush = true;
+}
+
+void
+QUICTLS::on_handshake_data_generated(QUICEncryptionLevel level, const uint8_t *data, size_t len)
+{
+ int index = static_cast<int>(level);
+ int next_index = index + 1;
+
+ size_t offset = this->_out.offsets[next_index];
+ size_t next_level_offset = offset + len;
+
+ memcpy(this->_out.buf + offset, data, len);
+
+ for (int i = next_index; i < 5; ++i) {
+ this->_out.offsets[i] = next_level_offset;
+ }
+}
+
+void
+QUICTLS::on_tls_alert(uint8_t alert)
+{
+ this->_has_crypto_error = true;
+ this->_crypto_error = QUICTLS::convert_to_quic_trans_error_code(alert);
+}
+
+bool
+QUICTLS::has_crypto_error() const
+{
+ return this->_has_crypto_error;
+}
+
+uint64_t
+QUICTLS::crypto_error() const
+{
+ return this->_crypto_error;
+}
+
+int
+QUICTLS::_handshake(QUICHandshakeMsgs **out, const QUICHandshakeMsgs *in)
+{
+ ink_assert(this->_ssl != nullptr);
+ if (this->_state == HandshakeState::ABORTED) {
+ return 0;
+ }
+
+ int err = SSL_ERROR_NONE;
+ ERR_clear_error();
+ int ret = 0;
+
+ SSL_set_msg_callback(this->_ssl, QUICTLS::_msg_cb);
+
+ this->_out.offsets[0] = 0;
+ this->_out.offsets[1] = 0;
+ this->_out.offsets[2] = 0;
+ this->_out.offsets[3] = 0;
+ this->_out.offsets[4] = 0;
+
+ if (in) {
+ this->_pass_quic_data_to_ssl_impl(*in);
+ }
+
+ if (this->_netvc_context == NET_VCONNECTION_IN) {
+ if (!this->_early_data_processed) {
+ if (auto ret = this->_read_early_data(); ret == 0) {
+ this->_early_data_processed = true;
+ } else if (ret < 0) {
+ return 0;
+ } else {
+ // Early data is not arrived yet -- can be multiple initial packets
+ }
+ }
+
+ ret = SSL_accept(this->_ssl);
+ } else {
+ if (!this->_early_data_processed) {
+ if (this->_write_early_data()) {
+ this->_early_data_processed = true;
+ }
+ }
+
+ ret = SSL_connect(this->_ssl);
+ }
+
+ if (ret <= 0) {
+ err = SSL_get_error(this->_ssl, ret);
+
+ switch (err) {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ break;
+ default:
+ char err_buf[256] = {0};
+ ERR_error_string_n(ERR_get_error(), err_buf, sizeof(err_buf));
+ Debug(tag, "Handshake: %s", err_buf);
+ return ret;
+ }
+ }
+
+ if (this->_should_flush) {
+ this->_should_flush = false;
+ *out = &this->_out;
+ } else {
+ *out = nullptr;
+ }
+
+ return 1;
+}
+
+void
QUICTLS::_update_encryption_level(QUICEncryptionLevel level)
{
if (this->_current_level < level) {
@@ -210,10 +502,10 @@ QUICTLS::_update_encryption_level(QUICEncryptionLevel level)
void
QUICTLS::_print_km(const char *header, const uint8_t *key_for_hp, size_t key_for_hp_len, const uint8_t *key, size_t key_len,
- const uint8_t *iv, size_t iv_len, const uint8_t *secret, size_t secret_len)
+ const uint8_t *iv, size_t iv_len, const uint8_t *secret, size_t secret_len, QUICKeyPhase phase)
{
if (is_debug_tag_set("vv_quic_crypto")) {
- Debug("vv_quic_crypto", "%s", header);
+ Debug("vv_quic_crypto", "%s - %s", header, QUICDebugNames::key_phase(phase));
uint8_t print_buf[128];
if (secret) {
QUICDebug::to_hex(print_buf, static_cast<const uint8_t *>(secret), secret_len);
@@ -227,3 +519,12 @@ QUICTLS::_print_km(const char *header, const uint8_t *key_for_hp, size_t key_for
Debug("vv_quic_crypto", "hp=%s", print_buf);
}
}
... 8059 lines suppressed ...